Ever Gauzy Onboarding UI 插件实战指南:从零构建新用户引导流程
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)是整个引导流程的引擎,按以下步骤执行:
- 读取 Stripe 会话(可选):调用
readRememberedCheckoutSession()读取注册表单记住的 Stripe Checkout Session。若用户是通过共享结账页(shared checkout)注册的买家,这个 session id 会随租户创建一起发送给 API,使 API 能在验证 Stripe 后立即把新租户关联到对应的 Stripe customer,而无需等待邮箱确认; - 创建租户:
this._tenantService.create({ name: organization.name, ...(stripeCheckoutSessionId ? { stripeCheckoutSessionId } : {}) }),随后clearRememberedCheckoutSession()清理会话残留; - 拉取最新用户信息:
this._usersService.getMe(['tenant'])重新获取带 tenant 关系的用户数据并写入Store; - 创建默认组织:
this._organizationsService.create({ ...organization, tenant, isDefault: true }),即把表单数据与刚创建的租户绑定,并标记为默认组织; - 刷新令牌:调用
getAccessTokenFromRefreshToken()——若Store中存在refresh_token,则通过_authService.refreshToken(refresh_token)换取新 access token 写回Store; - 注册员工(后台执行):
registerEmployeeFeature(organization, createdOrganization)不阻塞主流程; - 跳转完成页:
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 中完成两件关键初始化:
- 权限装载:调用
PermissionsService.getPermissions()获取当前用户的角色权限(IRolePermission[]),随后initializeUiPermissions将权限名数组flushPermissions()后loadPermissions(permissions)注入ngx-permissions,使后续*ngxPermissions指令能正确控制界面元素显隐; - 功能加载:
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 插件,本插件的模块装配、路由注册与服务调用链是一份可直接参考的范本。
参考资料
- 插件 README:packages/plugins/onboarding-ui/README.md
- 插件清单:packages/plugins/onboarding-ui/package.json
- 模块定义:packages/plugins/onboarding-ui/src/lib/onboarding.module.ts
- 路由注册:packages/plugins/onboarding-ui/src/lib/onboarding.routes.ts
- 租户引导组件:packages/plugins/onboarding-ui/src/lib/components/tenant-onboarding/tenant-onboarding.component.ts
- 完成页组件:packages/plugins/onboarding-ui/src/lib/components/onboarding-complete/onboarding-complete.component.ts