- 后端
- 前端
- 企业应用
- MCP 服务
【免费下载链接】ever-gauzy
Ever® Gauzy™ - Open Business Management Platform (ERP/CRM/HRM/ATS/PM) - https://gauzy.co
导读:
@gauzy/plugin-job-matching-ui是 Ever® Gauzy™ 开源商业管理平台(ERP/CRM/HRM/ATS/PM)中负责「职位匹配(Job Matching)」功能的 Angular UI 插件。本指南以该插件在仓库中的 README 与源码为主线,完整覆盖插件的构建、单元测试、发布与安装流程,并深入讲解其插件定义、路由注册、权限控制与导航动态显隐的实现原理,帮助读者掌握在 Gauzy 平台中以插件形式扩展职位模块、并将匹配功能接入 Jobs 菜单的完整实战方案。
插件概览与仓库位置
@gauzy/plugin-job-matching-ui是 Gauzy 平台面向职位匹配场景的 UI 插件库,声明为private: true的 npm 包,许可证为 AGPL-3.0,作者为 Ever Co. LTD。从仓库目录结构看,插件源码集中在 packages/plugins/job-matching-ui 下,核心源码结构如下:
packages/plugins/job-matching-ui/ ├── src/ │ ├── index.ts # 插件公共 API 出口 │ └── lib/ │ ├── job-matching-plugin.ts # 插件定义(PluginUiDefinition) │ ├── job-matching.module.ts # Angular 模块 + 插件生命周期钩子 │ ├── job-matching.routes.ts # 路由与页面注册配置 │ └── components/ │ └── job-matching/ │ ├── job-matching.component.ts │ ├── job-matching.component.html │ ├── job-matching.component.scss │ └── job-matching.component.spec.ts ├── ng-package.json # ng-packagr 打包配置 ├── project.json # Nx 项目目标(build/test/lint) ├── package.json # 包元数据与依赖声明 ├── jest.config.ts # Jest 单元测试配置 └── README.md # 插件说明文档该插件定位为「UI 插件」,本质是 Ever Gauzy 插件化架构中前端侧的扩展点之一。在project.json中其 tags 为["type:plugin", "type:plugin-extension-point"],并声明了对contracts、ui-config、ui-core三个库的隐式依赖,说明它构建于 Gauzy 统一的契约类型、UI 配置与核心服务之上。
构建、测试、发布与安装(README 核心工作流)
插件 README 完整给出了一个 Nx 库从构建到发布的四步工作流,以下逐一展开并结合仓库配置补充细节。
构建(Build)
使用 Nx 构建该库:
yarn nx build plugin-job-matching-ui从 project.json 可以看到,build目标使用@nx/angular:ng-packagr-liteexecutor,输出目录为{workspaceRoot}/dist/packages/plugins/job-matching-ui,并依赖dependsOn: ["^build"](即先构建其上游依赖库)。构建支持两种配置:
development(默认):使用 tsconfig.lib.json;production:使用 tsconfig.lib.prod.json。
此外package.json还提供了三个便捷脚本:
yarn lib:build # 等价于 nx build plugin-job-matching-ui --configuration=development yarn lib:build:prod # 等价于 nx build plugin-job-matching-ui --configuration=production yarn lib:watch # 开发监听模式,--watch --configuration=development打包配置由 ng-package.json 控制:入口文件为src/index.ts,产物目录为../../../dist/packages/plugins/job-matching-ui,并允许引用../../ui-core/static/styles下的共享样式路径。
运行单元测试(Unit Tests)
yarn nx test plugin-job-matching-uitest目标使用@nx/jest:jestexecutor,覆盖率输出到coverage/packages/plugins/job-matching-ui。测试配置见 jest.config.ts:基于根目录jest.preset.js,通过jest-preset-angular转换 TypeScript/HTML 模板,并配置了 Angular 测试所需的三个快照序列化器。
测试用例本身位于 job-matching.component.spec.ts,其关键点在于:由于JobMatchingComponent并非 standalone 组件,测试通过直接导入声明它的JobMatchingModule来获取模板所需的真实作用域,再执行fixture.detectChanges()验证组件能够成功创建。
发布(Publishing)
构建完成后进入发布步骤:
cd dist/packages/plugins/job-matching-ui npm publish构建产物目录与ng-package.json中的dest配置一致。需要注意的是,package.json中标明"private": true,这意味着本地发布到公共 npm registry 前,需要先在仓库内将该标记移除(或发布到私有 registry),否则npm publish会被 npm 拒绝。
安装(Installation)
在需要使用该插件的项目中安装:
npm install @gauzy/plugin-job-matching-ui # 或使用 yarn yarn add @gauzy/plugin-job-matching-ui安装时需留意其peerDependencies与engines约束(见 package.json):
peerDependencies:@angular/common与@angular/core均为21.0.7,要求宿主应用运行在对应的 Angular 版本之上;engines:要求node >= 22、yarn >= 1.22;- 运行时依赖还包括
@gauzy/contracts、@gauzy/plugin-ui、@gauzy/ui-core、@nebular/theme、@ng-select/ng-select、@ngx-translate/core、ngx-permissions、rxjs等,安装时这些库也需可解析。
插件定义与注册机制(源码深度解析)
该插件遵循 Gauzy 的「声明式插件注册」模式:只需导出一个PluginUiDefinition对象,即可在宿主应用中完成路由、导航与权限的注册。
JobMatchingPlugin 定义
核心定义位于 job-matching-plugin.ts:
export const JobMatchingPlugin: PluginUiDefinition = { id: 'job-matching', version: '0.1.0', location: 'jobs-sections', module: JobMatchingModule, permissionKeys: [PermissionsEnum.ORG_JOB_MATCHING_VIEW], routes: [JOB_MATCHING_PAGE_ROUTE as PluginRouteInput] };各字段含义如下:
| 字段 | 值 | 说明 |
|---|---|---|
id | job-matching | 插件唯一标识 |
version | 0.1.0 | 插件版本号 |
location | jobs-sections | 挂载位置:注册到 Jobs 区域的 section 扩展点 |
module | JobMatchingModule | 加载的 Angular 模块 |
permissionKeys | [PermissionsEnum.ORG_JOB_MATCHING_VIEW] | 访问控制所需权限 |
routes | [JOB_MATCHING_PAGE_ROUTE] | 声明式注册的路由配置 |
在宿主应用的 plugin-ui.config.ts 中,该插件通常作为JobsPlugin的子插件挂载:
plugins: [ JobsPlugin.init({ plugins: [ JobProposalPlugin, JobEmployeePlugin, JobSearchPlugin, JobMatchingPlugin, JobProposalTemplatePlugin ] }) ]这与源码注释中给出的示例用法一致,也印证了location: 'jobs-sections'的挂载语义——匹配页面被注册为 Jobs 导航分区下的一个 section。
公共 API 出口
src/index.ts 是插件的公共 API 表面(Public API Surface),导出内容包括插件定义、模块、路由配置以及页面组件,使用者可据此按需引用:
export * from './lib/job-matching-plugin'; export * from './lib/job-matching.module'; export * from './lib/job-matching.routes'; export * from './lib/components/job-matching/job-matching.component';路由注册与权限控制
页面路由配置
路由配置集中在 job-matching.routes.ts:
export const JOB_MATCHING_PATH = 'matching'; export const JOB_MATCHING_PAGE_LINK = `/pages/jobs/${JOB_MATCHING_PATH}`;匹配页面的完整访问路径为/pages/jobs/matching。插件通过JOB_MATCHING_PAGE_ROUTE以声明式方式注册该 section:
export const JOB_MATCHING_PAGE_ROUTE: PageRouteRegistryConfig = { location: 'jobs-sections', path: JOB_MATCHING_PATH, loadChildren: () => import('./job-matching.module').then((m) => m.JobMatchingModule), data: { selectors: { ...JOB_MATCHING_SELECTORS } } };其中data.selectors定义了页面顶部的筛选器组合(日期、员工可见,项目、团队隐藏):
const JOB_MATCHING_SELECTORS = { date: true, employee: true, project: false, team: false } as const;采用loadChildren懒加载,路由对应的实际页面组件由getJobMatchingRoutes()返回的Route[]提供,该函数在模块中以ROUTESprovider(multi: true)注入:
export function getJobMatchingRoutes(): Route[] { return [ { path: '', component: JobMatchingComponent, canActivate: [PermissionsGuard], data: { permissions: { only: [PermissionsEnum.ORG_JOB_MATCHING_VIEW], redirectTo: '/pages/dashboard' } } } ]; }这里有两个值得注意的安全细节:
canActivate: [PermissionsGuard]:进入页面必须通过权限守卫校验;redirectTo: '/pages/dashboard':无权限用户将被重定向到仪表盘,而非简单拒绝访问。
模块装配
JobMatchingModule 声明了唯一的JobMatchingComponent,并引入NebularModule、TranslateModule、NgSelectModule、SharedModule、DialogsModule等 UI 基础设施,同时通过ROUTESprovider 将上述路由注册到 Angular 路由器中。
插件生命周期与导航动态显隐
JobMatchingModule实现了IOnPluginUiBootstrap与IOnPluginUiDestroy两个插件生命周期接口,这是它区别于普通 Angular 模块的核心特性。
启动与销毁钩子
ngOnPluginBootstrap():插件模块被PluginUiModule实例化后调用,内部执行_applyDeclarativeRegistrations()与_subscribeToJobMatchingEntity();ngOnPluginDestroy():应用关闭时调用,重置注册标记(_hasAppliedRegistrations = false),并通过_destroy$Subject 统一退订所有流,避免内存泄漏。
声明式注册(幂等保护)
_applyDeclarativeRegistrations()借助静态标记_hasAppliedRegistrations保证整个应用生命周期内只执行一次:
if (JobMatchingModule._hasAppliedRegistrations || !this._pluginDefinition) return; applyDeclarativeRegistrations(this._pluginDefinition, { navBuilder: this._navMenuBuilderService, pageRouteRegistry: this._pageRouteRegistryService });即把插件定义中的路由与导航项一次性注入PageRouteRegistryService(页面路由注册表)与NavMenuBuilderService(导航菜单构建器)。
基于同步状态动态显隐「Matching」菜单
插件还订阅了IntegrationEntitySettingServiceStoreService.jobMatchingEntity$可观察流,根据职位匹配同步是否开启,动态增删 Jobs 分区下的「Matching」导航项:
map(({ currentValue }) => !!currentValue?.sync && !!currentValue?.isActive), distinctUntilChange(), takeUntil(this._destroy$), tap((isActive: boolean) => (isActive ? this._addNavMenuItem() : this._removeNavMenuItem()))sync与isActive同时为真时才视为「激活」;- 流异常时通过
catchError回退为{ sync: false, isActive: false },保证异常场景下导航项安全隐藏; distinctUntilChange避免重复增删。
新增菜单项时指定了唯一 idjobs-matching、标题Matching、FontAwesome 图标fas fa-user、链接/pages/jobs/matching,以及翻译键MENU.JOBS_MATCHING与权限键ORG_JOB_MATCHING_VIEW,并作为jobs-proposal-template之后的兄弟项插入 Jobs 分区:
this._navMenuBuilderService.addNavMenuItem( { id: 'jobs-matching', title: 'Matching', icon: 'fas fa-user', link: JOB_MATCHING_PAGE_LINK, data: { translationKey: 'MENU.JOBS_MATCHING', permissionKeys: [PermissionsEnum.ORG_JOB_MATCHING_VIEW] } }, 'jobs', 'jobs-proposal-template' );页面组件与业务能力
JobMatchingComponent(selector:ga-job-matching)是匹配页面的实际业务载体,位于 job-matching.component.ts。其核心能力包括:
权限与国际化初始化
组件初始化时执行initializeUiPermissions()(从用户角色权限中加载到ngx-permissions)与initializeUiLanguagesAndLocale()(订阅语言偏好并切换@ngx-translate当前语言)。源码中特别提醒:权限绑定必须使用Object.freeze冻结的稳定数组常量,避免每次变更检测周期生成新数组导致ngx-permissions无限重校验、卡死主线程。
数据模型与响应式加载
- 通过
payloads$(BehaviorSubject)以 100ms 防抖合并组织/员工选择,请求职位预设(JobPresetService.getJobPresets); - 订阅
selectedOrganization$与selectedEmployee$,用combineLatest联动刷新类别、职业与员工匹配标准; - 请求载荷
IGetJobPresetInput统一携带tenantId、organizationId,选择员工时附带employeeId。
匹配标准(Criterion)管理
组件围绕IMatchingCriterions提供完整的增删改查:
- 新增:
addNewCriterion()默认插入{ jobType: JobPostTypeEnum.HOURLY }的空标准; - 保存:
saveCriterion()区分两种作用域——选中员工时调用createEmployeeCriterion(employeeId, ...)保存为员工级标准,否则调用createJobPresetCriterion(jobPresetId, ...)保存为预设级标准; - 删除:
deleteCriterions(index, criterion)同样区分员工级与预设级删除,删除后若列表为空会自动补一条新标准; - 预设:
addPreset(name)可即时创建职位预设并绑定当前员工;saveJobPreset()在提交前会用omit(item, 'employeeId', 'id', 'jobPresetId')剔除服务端字段后再序列化标准列表。
类别与职业维护
组件还支持内联创建职位搜索类别(createNewCategories)与职业(createNewOccupations),数据源为JobSearchCategoryService与JobSearchOccupationService,均按tenantId + organizationId + jobSource维度过滤,默认数据源为JobPostSourceEnum.UPWORK。
质量保障与工程约束小结
- 测试:
yarn nx test plugin-job-matching-ui提供组件冒烟测试,覆盖插件模块导入与组件实例化路径; - Lint:
project.json中配置了@nx/eslint:lint目标,可在yarn nx lint plugin-job-matching-ui下执行; - 版本:插件与包版本均为
0.1.0,CHANGELOG.md目前仅有[Unreleased]段,尚无可发布的历史版本记录; - 依赖边界:
sideEffects: false允许打包器对未使用导出做 tree-shaking,属于 Angular 库的标准工程化约定。
以上内容完整覆盖了 README 的构建、测试、发布、安装四个标准流程,并进一步从插件定义、路由、权限、生命周期与业务组件五个层面还原了该插件的源码实现,可作为在 Ever Gauzy 平台中集成、扩展与二次开发 Job Matching 功能的直接参考。
- 后端
- 前端
- 企业应用
- MCP 服务
【免费下载链接】ever-gauzy
Ever® Gauzy™ - Open Business Management Platform (ERP/CRM/HRM/ATS/PM) - https://gauzy.co
相关推荐
Ever Gauzy AI 集成 UI 插件(@gauzy/plugin-integration-ai-ui)开发实践与源码解析
Ever Gauzy AI 集成 UI 插件(@gauzy/plugin integration ai ui)开发实践与源码解析 Ever® Gauzy™ 的
后端前端企业应用MCP 服务在 Ever Gauzy 中集成 Activepieces:@gauzy/plugin-integration-activepieces-ui 插件深度解析
在 Ever Gauzy 中集成 Activepieces:@gauzy/plugin integration activepieces ui 插件深度解析 导
后端前端企业应用MCP 服务Ever Gauzy 视频管理 UI 插件 `@gauzy/plugin-videos-ui` 完整实战指南
Ever Gauzy 视频管理 UI 插件 @gauzy/plugin videos ui 完整实战指南 @gauzy/plugin videos ui 是 E
后端前端企业应用MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考