- 后端
- 前端
- 企业应用
- MCP 服务
【免费下载链接】ever-gauzy
Ever® Gauzy™ - Open Business Management Platform (ERP/CRM/HRM/ATS/PM) - https://gauzy.co
本篇技术指南围绕 Ever® Gauzy™ 开源业务管理平台(ERP/CRM/HRM/ATS/PM)中的商品评论插件@gauzy/plugin-product-reviews展开,完整覆盖该插件的构建、单元测试、发布与安装流程,并结合仓库源码深入剖析其ProductReview实体结构、审核状态机、多 ORM 仓储实现与 GraphQL 扩展原理。读完本文,你将掌握如何在 Gauzy 平台中集成商品评价能力、理解其数据模型与生命周期钩子,并能独立完成该插件库的构建与发布。
插件定位:为 Gauzy 平台注入商品评价能力
@gauzy/plugin-product-reviews是 Ever Gauzy 插件体系(位于 packages/plugins/product-reviews)中负责商品评论/评价管理的独立库。从该库的 package.json 可见其官方描述为 "Gauzy Product Reviews Plugin - Integration for managing and displaying product reviews in the Gauzy Platform",即它是平台中管理商品评论的集成模块。
在 Gauzy 的插件机制中,该插件被注册进 API 服务端。从 apps/api/src/plugins.ts 可以看到:
import { ProductReviewsPlugin } from '@gauzy/plugin-product-reviews'; // 插件列表中注册 ProductReviewsPlugin,这表明它作为平台可插拔能力的一部分,随 API 服务启动时被加载。其project.json中声明了"tags": ["type:plugin"],与其它 Gauzy 插件保持一致。
快速开始:构建、测试、发布与安装
本插件的 README.md 给出了完整的工作流。以下所有命令均需在仓库根目录执行(项目使用 Nx 作为构建编排工具)。
构建插件库
yarn nx build plugin-product-reviews该命令通过 Nx 执行编译,产出目录为dist/packages/plugins/product-reviews。从 project.json 可以看到构建目标的具体配置:
- 执行器:
@nx/js:tsc(基于 TypeScript 编译器) - 输出路径:
dist/packages/plugins/product-reviews - 入口文件:
packages/plugins/product-reviews/src/index.ts - 编译配置:
packages/plugins/product-reviews/tsconfig.lib.json - 资源复制:
packages/plugins/product-reviews/*.md(README 等文档会随包一起产出) - 依赖约束:
"dependsOn": ["^build"],即会先构建其依赖的contracts、core、plugin等隐式依赖库(见implicitDependencies)
package.json中还封装了三个便捷脚本:
"scripts": { "lib:build": "yarn nx build plugin-product-reviews", "lib:build:prod": "yarn nx build plugin-product-reviews", "lib:watch": "yarn nx build plugin-product-reviews --watch" }--watch模式适用于开发迭代,改动源码后自动增量编译。
运行单元测试
yarn run test plugin-product-reviews该命令通过 Nx 的 Jest 执行器(@nx/jest:jest)运行测试,配置指向 packages/plugins/product-reviews/jest.config.ts,覆盖率输出到coverage/packages/plugins/product-reviews。项目根目录的 jest.config.ts 与 jest.preset.js 提供了统一的 Jest 预设。
发布到 npm
构建完成后,进入产物目录并发布:
cd dist/packages/plugins/product-reviews npm publishproject.json中为此配置了nx-release-publish目标(packageRoot 指向dist/{projectRoot}),说明仓库支持通过 Nx 的发布流程管理版本。值得注意的是,当前 package.json 中"private": true且版本为0.1.0,表示该插件目前主要在仓库内部/工作区消费,实际对外发布前需移除 private 标记并按需调整版本号。
安装插件
在需要使用该插件的项目中,用你偏好的包管理器安装:
npm install @gauzy/plugin-product-reviews # or yarn add @gauzy/plugin-product-reviews由于该插件是平台的扩展模块,安装后还需在应用的模块配置中将其引入(如 apps/api/src/plugins.ts 所示),使其实体与生命周期钩子生效。
插件核心实现:装饰器、生命周期与导出面
插件类与声明式配置
插件主体的实现位于 src/lib/product-reviews.plugin.ts,源码如下(关键部分):
import * as chalk from 'chalk'; import { GauzyCorePlugin as Plugin, IOnPluginBootstrap, IOnPluginDestroy } from '@gauzy/plugin'; import { ProductReview } from './entities/product-review.entity'; import { schemaExtensions } from './graphql/schema-extensions'; @Plugin({ imports: [], entities: [ProductReview], extensions: { schema: schemaExtensions, resolvers: [] } }) export class ProductReviewsPlugin implements IOnPluginBootstrap, IOnPluginDestroy { // We disable by default additional logging for each event to avoid cluttering the logs private logEnabled = true; onPluginBootstrap(): void | Promise<void> { if (this.logEnabled) { console.log(chalk.green(`${ProductReviewsPlugin.name} is being bootstrapped...`)); console.log('ReviewsPlugin is being bootstrapped...'); } } onPluginDestroy(): void | Promise<void> { if (this.logEnabled) { console.log(chalk.red(`${ProductReviewsPlugin.name} is being destroyed...`)); } } }可以拆解出三层关键信息:
@Plugin装饰器:来自@gauzy/plugin包,负责把类声明为 Gauzy 平台的插件。声明内容包含:imports: []:可导入其它模块(当前为空);entities: [ProductReview]:把ProductReview实体注册进平台的数据层,使其被 ORM 自动建表/同步;extensions.schema:注入 GraphQL schema 扩展;extensions.resolvers:预留的解析器数组(当前为空,说明 GraphQL 数据操作主要依赖平台默认 CRUD 机制)。
生命周期钩子:实现了
IOnPluginBootstrap(插件初始化时触发)与IOnPluginDestroy(插件销毁时触发)。代码使用chalk对日志着色(绿色表示启动、红色表示销毁),并注释说明默认启用日志但可通过logEnabled关闭,以避免刷屏。命名细节:启动日志同时打印了类名与
'ReviewsPlugin'字样,这与后续实体命名统一为ProductReview略有出入,属于代码中保留的历史命名痕迹。
公共 API 导出面
src/index.ts 定义了库的公共 API 表面:
export * from './lib/product-reviews.plugin'; export * from './lib/entities'; export * from './lib/graphql/schema-extensions';即对外暴露:插件类、实体(经由 entities/index.ts 再导出ProductReview)、以及 GraphQL schema 扩展。
数据模型:ProductReview 实体的完整字段
商品评论的数据结构定义在 src/lib/entities/product-review.entity.ts。该实体继承自 Gauzy 核心的TenantOrganizationBaseEntity(因此天然携带租户与组织维度,适合多租户 SaaS 场景),并标注了@MultiORMEntity('product_review', ...),表名为product_review。
核心字段与校验规则
| 字段 | 类型 | 约束/校验 | 说明 |
|---|---|---|---|
title | string | 可选(@IsOptional),可空 | 评论标题 |
description | string | 可选,text类型可空 | 评论正文 |
rating | number | 必填,0 ≤ rating ≤ 10 | 评分(@Min(0)/@Max(10)) |
upvotes | int | 默认0,带索引 | 赞成票数 |
downvotes | int | 默认0,带索引 | 反对票数 |
status | varchar | 枚举校验,默认pending | 审核状态 |
editedAt | timestamp/text | 可空,带索引 | 最近编辑时间 |
isEdited | boolean | 虚拟列 | 是否被编辑过(由editedAt派生) |
逐项说明:
rating:通过class-validator的@IsNotEmpty()、@IsNumber()、@Min(0)、@Max(10)强约束,Swagger 文档(@ApiProperty)中同样标注minimum: 0, maximum: 10,评分体系为 0–10 分制。upvotes/downvotes:均为int类型、默认值 0,且都带有@ColumnIndex()索引——若后续需要按票数排序或筛选,数据库层面已有索引支撑。status:默认值为ProductReviewStatusEnum.PENDING,即新评论默认进入"待审核"状态。editedAt与isEdited:editedAt是真实存储列;isEdited是@VirtualMultiOrmColumn()虚拟列,不会落库,而是由 ORM 在读取时派生(判断editedAt是否存在)。editedAt的类型兼容:源码中@MultiORMColumn({ type: isBetterSqlite3() ? 'text' : 'timestamp' })依据@gauzy/config的isBetterSqlite3()运行时判断数据库类型——使用 better-sqlite3 时存为text,否则存为timestamp,这是 Gauzy 多数据库支持(TypeORM + MikroORM)的典型写法。
关联关系
实体与产品、用户建立了多对一关联,且删除时级联(onDelete: 'CASCADE'):
product?/productId?:被评论的Product实体。@MultiORMManyToOne(() => Product)+@JoinColumn(),productId为@IsUUID()校验的关联 ID 列(@RelationId+relationId: true),带索引。user?/userId?:发表评论的User实体,同样级联删除并带@ColumnIndex()的userId关联列。
这种设计意味着:删除产品或其所属用户时,相关评论会一并删除;同时通过productId/userId索引可以高效地按产品或用户查询评论集合。
审核状态机与类型契约
评论状态定义在 src/lib/product-review.types.ts:
export type ProductReviewStatus = 'approved' | 'pending' | 'rejected'; export enum ProductReviewStatusEnum { APPROVED = 'approved', PENDING = 'pending', REJECTED = 'rejected' } export interface IProductReview extends IBasePerTenantAndOrganizationEntityModel { title: string; description: string; rating: number; upvotes: number; downvotes: number; status: ProductReviewStatus; product?: IProduct; productId?: ID; user?: IUser; userId?: ID; }三态审核流程:新评论创建时默认pending,经平台管理操作可流转为approved(对外展示)或rejected(隐藏/拒绝)。IProductReview接口继承IBasePerTenantAndOrganizationEntityModel,保证了评论天然具备租户与组织归属。从源码结构看,isEdited与editedAt字段在接口中未显式声明,属于实体层面的派生/附加字段。
多 ORM 仓储实现
Gauzy 平台同时支持 TypeORM 与 MikroORM,本插件为两种 ORM 各提供了仓储实现(位于 src/lib/entities/repository):
- mikro-orm-product-review.repository.ts:继承
MikroOrmBaseEntityRepository<ProductReview>,空实现即获得基础 CRUD 能力,并在实体上通过@MultiORMEntity(..., { mikroOrmRepository: () => MikroOrmProductReviewRepository })绑定。 - type-orm-product-review.repository.ts:
@Injectable()的 NestJS 服务类,继承 TypeORM 的Repository<ProductReview>,构造器通过@InjectRepository(ProductReview)注入底层仓储并透传给父类。
这种"一套实体 + 双仓储"的结构,让插件无论运行在哪种 ORM 模式下都能获得一致的数据访问能力,是 Gauzy 跨数据库抽象(MultiORM*系列装饰器)在业务插件中的直接体现。
GraphQL Schema 扩展
插件通过 src/lib/graphql/schema-extensions.ts 向平台的 GraphQL API 注入类型定义:
import { gql } from 'graphql-tag'; export const schemaExtensions = gql` type ProductReview { id: ID! body: String rating: Float! } `;它声明了ProductReviewGraphQL 类型(id、body、rating),并通过@Plugin的extensions.schema合并进平台 schema。注意该 GraphQL 类型与 ORM 实体字段并不完全一一对应(例如 GraphQL 层使用body而非description,且未暴露状态字段),从源码结构看这更像一个最小化的对外契约骨架;由于resolvers目前为空数组,完整的数据操作仍依赖平台默认的查询/变更机制。若要在实际业务中公开更多字段(如status、upvotes、productId),需要同步扩展此处的 schema 定义。
依赖与运行环境
从 package.json 可确认以下工程约束:
- Node/Yarn 版本要求:
engines声明node >= 22、yarn >= 1.22,构建与运行前需保证环境满足。 - 运行时依赖:
@gauzy/contracts、@gauzy/core、@gauzy/plugin(平台核心)、@nestjs/common/@nestjs/core(peerDependencies,^11.1.26)、@nestjs/swagger、@nestjs/typeorm、typeorm、class-validator、graphql-tag、chalk、tslib。 - 许可与归属:AGPL-3.0 许可,作者为 Ever Co. LTD(ever@ever.co)。
- 关键词:
gauzy、product-reviews、plugin、nestjs、typescript、reviews、feedback、e-commerce——即面向电商场景的评价/反馈能力。
总结:从接入到扩展的完整路径
围绕@gauzy/plugin-product-reviews,可以梳理出一条清晰的实战路径:
- 接入:在 Gauzy 应用(如 apps/api/src/plugins.ts)中导入并注册
ProductReviewsPlugin,其entities: [ProductReview]会让product_review表随平台同步创建; - 使用:通过多 ORM 仓储(TypeORM/MikroORM)执行评论 CRUD,遵循
rating0–10、status三态(pending/approved/rejected)等校验与状态约定; - 构建发布:
yarn nx build plugin-product-reviews产出dist/packages/plugins/product-reviews,再经npm publish发布;也可通过yarn add @gauzy/plugin-product-reviews直接安装使用; - 扩展:如需对外暴露更多评论字段,可在 schema-extensions.ts 中扩展 GraphQL 类型,并在插件
resolvers中补充解析逻辑。
该插件体现了 Gauzy 插件体系的典型范式:声明式@Plugin元数据 + 生命周期钩子 + 多 ORM 实体 + GraphQL schema 扩展,为在 ERP/电商业务中快速叠加商品评价模块提供了可复制的工程样板。
- 后端
- 前端
- 企业应用
- MCP 服务
【免费下载链接】ever-gauzy
Ever® Gauzy™ - Open Business Management Platform (ERP/CRM/HRM/ATS/PM) - https://gauzy.co
相关推荐
Ever Gauzy 插件化 UI 开发指南:基于 @gauzy/plugin-ui 构建可插拔前端模块
Ever Gauzy 插件化 UI 开发指南:基于 @gauzy/plugin ui 构建可插拔前端模块 @gauzy/plugin ui 是 Ever Gau
后端前端企业应用MCP 服务Ever Gauzy 集成 OpenAI GPT:`@gauzy/plugin-ai-provider-openai` 插件配置与源码剖析
Ever Gauzy 集成 OpenAI GPT: @gauzy/plugin ai provider openai 插件配置与源码剖析 本文围绕 Ever®
后端前端企业应用MCP 服务Ever Gauzy 的 Zapier 集成 UI 插件:从构建、测试到发布与安装的完整指南
Ever Gauzy 的 Zapier 集成 UI 插件:从构建、测试到发布与安装的完整指南 导读 @gauzy/plugin integration zapi
后端前端企业应用MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考