关于 cpq-builder
CPQ Builder 是用于构建原型的技能,帮助工具收集结构化输入、应用业务规则,并生成供审查或审批的交付物。它提供可适配不同领域的产品报价、计算器和信息收集流程模式。
主要功能
- 01直接编辑报价明细
- 02产品组合与可见约束规则
- 03透明展示折扣计算
- 04实时汇总与品牌报价输出
- 05审批路由与角色视图
- 06保存、加载、克隆和管理报价
适用场景
- 01替代基于电子表格的报价流程
- 02构建产品配置与定价工具
- 03制作资格或保险估算器
- 04原型化可审查的业务提案
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ customware-ai/ skills --skill cpq-builder安装后在 Claude Code 中输入/cpq-builder确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/config-schema.mdexample-config.jsonvertical-presets.md详细介绍
CPQ 构建技能
此技能的作用
此技能定义了构建 Configure-Price-Quote(配置、定价、报价)类工具的模式:用户配置输入项,系统应用规则计算结果,最终生成可能需要审核/批准的格式化交付物。
CPQ 并不局限于产品定价。相同的结构模式适用于:
| 领域 | “配置” | “计算” | “输出” |
|---|---|---|---|
| 设备销售 | 选择产品、挑选选项 | 应用加价、计算总额 | 销售报价 PDF |
| 法律计算器 | 输入案件详情(收入、期限) | 应用指导原则公式 | 含估算值的摘要报告 |
| 保险估算器 | 输入保障详情 | 应用费率表 | 保费估算文件 |
| 贷款资格审核 | 输入财务详情 | 应用贷款标准 | 资格确认函 |
| 福利资格审核 | 输入个人详情 | 应用资格规则 | 福利摘要 |
| 服务方案 | 选择服务、设定范围 | 应用人工费率 | 服务方案 |
构建器会读取此技能,读取特定领域的 DOMAIN.md 以了解术语和规则,然后生成可用的原型。DOMAIN.md 决定工具是用于起重机报价还是离婚计算;此技能提供适用的结构模式。
此技能中的模式是默认方案,而非强制要求。 如果实际工作流偏离了标准 CPQ 结构——阶段较少、布局不同或输出不同——请调整这些模式。每个主要章节都会明确说明相应的偏差。
客户背景
Customware 的 CPQ 客户涵盖众多领域:工业设备经销商、定制服装和标牌店、食品/饮料批发商、专业服务公司(法律、咨询、设计)、IT 和托管服务提供商、建筑和工程企业、制造商、分销商。CPQ 模式适用于所有这些领域。
此技能中的示例会轮换使用多个领域——工业设备、服务、消费品、软件、定制商品。这是有意为之。这些模式不依赖特定领域;示例通过类比加以说明。应用此技能时,请忽略任一示例中的具体领域,提炼出其结构模式。构建时,DOMAIN.md 会决定具体的用语、产品、规则和角色。
“单梁起重机需要电机”这一规则,与“定制连帽衫需要选择印刷方式”或“托管服务合同需要选择服务等级”或“狗零食订单需要选择包装规格”的结构相同。这类规则的模式是“父级产品要求选择子级组件”。构建该模式;具体措辞由 DOMAIN.md 提供。
客户画像
Customware 的 CPQ 客户通常是成长中遇到瓶颈的中小型企业(5-50 名员工)。他们不是从其他 CPQ 系统迁移而来,而是从以下方式迁移:
- 已经变得难以管理的 Excel 电子表格(多个选项卡、复制粘贴错误、公式失效)
- 每次都要针对客户手动编辑的 Word 文档报价模板
- 基于电子邮件的审批工作流:老板在回复所有人的邮件线程中批准报价
- 关于哪些产品需要搭配哪些配件的经验知识,这些知识只存在于资深销售代表的脑海中
- 手动输入价格,折扣不一致导致利润率不断缩水
原型的任务是让用户感觉比电子表格好得多,同时又不会复杂得像企业级软件。一个 5 年来一直用 Excel 报价的小团队看到原型后,应该立刻觉得“这快多了”,而不是“这看起来好复杂”。
这一定位会影响本技能中的每项设计决策:
- 行内编辑明细行是主要比较点。Excel 用户希望能直接编辑表格。
- 实时总计很重要。客户一直用公式计算,因此希望看到数字随着输入内容的变化而更新。
- 角色权限限制令人印象深刻。客户从未见过通过软件强制执行“只有所有者才能批准超过 50K 的金额”这类规则——过去这只是口头规定,而且经常被违反。
- 品牌化 PDF 输出令人印象深刻。客户以前一直在 Word 文档中手动调整格式。
- 面向客户的门户、AI 建议、电子签名集成在这个阶段并不令人印象深刻。它们属于企业级复杂功能,解决的是客户目前尚未遇到的问题。
服务于那些厌倦了 Excel 公式失效的客户,而不是从 Salesforce 迁移来的客户。
这真的算 CPQ 吗?
在应用本技能中的任何模式之前,请先确认工作流确实符合 CPQ 特征。只有以下四项全部成立时,CPQ 模式才适用:
- 用户收集结构化输入,这些输入决定最终结果(配置选项、客户详情、需求、财务数据、案例详情)。
- 业务规则或计算逻辑会转换这些输入,生成交付物(加价公式、准则计算、费率表、资格规则)。
- 输入与最终确定之间存在审核或审批关卡,或者交付物需要经过某种利益相关方审核(准备者/审核者模式)。
- 工作成果看起来需要移交给他人——客户、内部利益相关方、监管机构或下游系统。
缺少标准 1 → 这是仪表板或展示工具,不是 CPQ。停止。 缺少标准 2 → 这是数据录入表单,不是 CPQ。停止。 缺少标准 3 → 这是“收集后交付”流程——应用 CPQ 模式,但跳过“审批”部分。 缺少标准 4 → 这是个人计算器/实用工具,不是 CPQ。停止。
常见误判:
- “股票报价查看器”——虽然名称中有“报价”,但它是展示工具(缺少标准 1)
- 没有审核步骤的“税务计算器”——这是实用工具,不是 CPQ(缺少标准 3 和 4)
- 带有价格的“产品目录”——这是展示工具,不是 CPQ(缺少标准 2 和 3)
- “反馈表单”——这是数据录入工具,不是 CPQ(缺少标准 2)
如果不满足这四项标准,请勿强行套用以下模式。请根据任务描述和 DOMAIN.md,改用 frontend-design 的原则进行构建。
领域类型
大多数 CPQ 工作流分为两种领域类型。应用模式之前,先确定构建属于哪种类型:
产品领域。 用户配置可销售的产品/服务。定价是核心计算。输出为报价文档,其中包含行项目、总计、税费和条款。示例:设备销售、定制服装订单、食品/消费品批发、服务方案(咨询投标、托管服务)、软件许可、定制包装。
计算器/信息采集领域。 用户输入案例/申请人详情。计算会应用指南/规则/费率表。输出为摘要报告,其中包含输入项、计算值和免责声明。示例:配偶赡养费计算器(Clarity Legal)、保险估算器、贷款资格评估、福利资格评估。
本技能中的模式适用于这两种领域。当某个章节或规则仅适用于特定领域时,本技能会明确说明。
最低标准
每个 CPQ 构建都必须符合 Tier 1 标准。当 DOMAIN.md 表明有此需求时,再构建 Tier 2 标准。Tier 3 功能会在完成摘要中作为未来工作提及,但不会在原型中构建。
Tier 1 — 不可妥协(适用于每个 CPQ 构建)
这些功能能让原型显著优于 Excel + Word。如果缺少任何一项,无论 UI 看起来多么整洁,构建都不完整。
1. 直接内联编辑行项目。 提供类似电子表格的表格,让用户添加行、编辑任意单元格,并实时查看总计更新。不能采用“配置表单 → 添加到报价 → 构建报价表格 → 编辑”的往返流程。行项目表格本身就是工作区。规范实现请参见下方的“章节模式”。
2. 套装/必需子产品采用合适的配置器模式。 当父产品需要子组件时(例如,“工业设备需要选择电机”“定制连帽衫需要选择印花方式”“托管服务合同需要选择等级”“狗零食订单需要选择包装规格”),配置父产品时就应包含子产品选择。行项目应将父产品和所选子产品显示为一个完整条目。绝不能拆成两个独立行项目,以免用户忘记选择子产品。对于包含 4 项以上配置属性或存在级联依赖的产品(典型的工业设备、定制商品和分级服务通常会深入 3-4 层),应采用合适的配置器模式——关于内联展开、侧边抽屉或整页的选择,请参见下方的“产品配置器模式”。
3. 明确展示约束规则。 DOMAIN.md 中的必需/排除/推荐规则必须向用户清晰可见,不能只在后台静默执行。用户添加起重机时,UI 应在用户保存之前显示“必须选择电机(BR-001)”。用户尝试添加不允许的组合时,UI 应显示相关规则及其原因。习惯使用 Excel 的客户从未经历过规则强制执行——让规则清晰可见,就体现了产品的一半价值。
4. 清晰展示折扣叠加计算。 应用折扣时,展示分层计算:
List Price: $15,000.00
Volume Discount (5%): -$750.00
Promotional Discount (3%): -$427.50
─────────────────────────────────────
Net Price: $13,822.50
每项折扣都应单独列出,计算过程一目了然。过去在没有审计记录的电子邮件往来中协商折扣的客户,需要清楚了解价格的具体计算过程。
5. 实时报价摘要。 用户编辑行项目时,小计、税费和总计等累计金额应实时更新。不应设置“点击计算”按钮。这是从 Excel 转来的客户感受最强烈的“惊艳时刻”——总计会自动更新。
6. 品牌化报价文档。 生成的 PDF/打印视图应包含客户徽标、行项目表、总计、条款及任何必需的免责声明。该文档取代手动排版的 Word 文档。质量标准:外观应达到真实企业会发送的报价水平。 7. 多层审批路由。 大多数中小企业工作流至少有 2 个审批级别(销售代表配置 → 经理审核 → 所有者批准)。即使是简单情况,也至少有一位审批人和一位最终签字人。原型必须展示基于角色的路由,并遵循 DOMAIN.md 的利益相关者关系图。路由通常会根据请求类型分支,例如,一家公司可能会将“自定义配置交由高级审核人审批,检查交由服务经理审批,维护交由运营经理审批,而所有路径的最终审批人都是所有者”。这种条件式多层路由是必备功能。
8. 多报价管理。 用户会同时处理多个报价。原型必须展示带状态指示器的报价列表,支持筛选和排序,并允许用户点击任意报价进行编辑。不能只有一个报价工作区,再加上一个“已保存报价”的侧边栏列表。
9. 保存/加载/克隆报价。 基于 localStorage 实现。用户可以创建新报价、保存报价、加载已保存的报价,并克隆现有报价以此为基础创建类似报价。Excel 用户会通过复制工作表来实现这一点;原型则提供“克隆”按钮。
10. 按角色控制视图和操作权限。 不同角色看到的内容不同。审批人可以看到“批准”按钮;准备人员看不到。非审批人看不到敏感数字(利润率、成本)。这就是“只有老板才能看到利润率”的模式,客户对此直观易懂,但过去从未真正落实过。
第 2 级 — 仅在 DOMAIN.md 有依据时构建
这些能力很有价值,但只有在 DOMAIN.md 提供明确信号时才值得构建。
- 引导式销售(针对复杂配置的分步问答)——当 DOMAIN.md 描述了与客户进行的需求发现流程时
- 批量/阶梯定价——当 DOMAIN.md 提及批量折扣、数量阶梯或批量优惠时
- 面向客户的只读报价链接——当 DOMAIN.md 提及通过电子邮件向客户发送报价或与客户分享报价时
- 订阅/续约处理——当领域类似 SaaS 且具有经常性收入时
- 在一次构建中支持多种定价模式(成本加成 + 目录定价 + 自定义定价)——当 DOMAIN.md 描述了混合定价策略时
- 按客户类型区分的报价文档模板——当 DOMAIN.md 描述了面向不同受众的不同输出格式时
第 3 级 — 后续工作(在完成摘要中提及,不要构建)
这些功能属于生产级构建,而非原型。完成摘要应列出这些功能,让客户了解接下来会有哪些内容。
- 根据 CRM/电子邮件/通话上下文由 AI 推荐报价
- 报价版本管理和修订跟踪
- 订阅计费逻辑和按比例计费
- CRM/ERP 集成(在全栈阶段处理)
- 电子签名集成(DocuSign、HelloSign 等)
- 税务引擎集成(Avalara、Vertex)
- 支持动态外汇汇率的多币种功能
- 客户自助配置门户
- 交易室/品牌化提案微型网站
- 原生移动应用
完成摘要模板
每个 CPQ 构建的完成摘要必须包含:
## What this prototype includes
**Tier 1 (always built):**
- [confirm each Tier 1 capability is present, or note why a specific one was omitted]
**Tier 2 (built for this domain):**
- [list any Tier 2 capabilities that were built and why]
## What this prototype does NOT include
This is a frontend prototype demonstrating the core CPQ workflow. The following capabilities
would come in production:
- [list relevant Tier 3 items based on the customer's likely future needs]
To move from prototype to production, add: real authentication, CRM/ERP integration,
e-signature, real PDF generation, and any Tier 3 capabilities listed above.
这样既能让客户清楚了解已交付的内容,又能坦诚说明还有更多功能即将推出。
何时使用此技能
当“这算 CPQ 吗?”中的四项标准均满足,且客户的 DOMAIN.md 包含以下内容时:
经典 CPQ 信号:
- 面向客户报价或定价的产品或服务
- 配置选项(尺寸、型号、变体、材料)
- 产品之间的依赖关系(必需、推荐、排除)
- 基于加价或利润率的定价(成本加成、供应商价目表 + 百分比)
- 报价或提案工作流(草拟 → 审核 → 批准 → 发送)
更广泛的“配置-计算-输出”信号:
- 带有审核/交接步骤的计算器、估算工具或评估工具
- 输入项会影响计算结果的引导式信息收集表单
- 应用规则以生成结果的多步骤数据收集
- 输出文档(报告、摘要、估算、提案)
- 填写者/审核者工作流(客户填写 → 专业人员审核)
**以下情况请勿使用此技能:**如果该领域主要涉及库存跟踪(使用 ERP 技能)、带有现场跟踪和付款的持续项目执行(使用 trades-builder)、在线产品销售(使用电商技能)或客户关系管理(使用 CRM 技能)。
模板约定
开始构建前,请先了解模板提供的内容,以及此技能会补充的内容:
模板(app/layouts/MainLayout.tsx)自带:
SidebarProvider、Sidebar、SidebarContent、SidebarInset、SidebarTrigger— 均已完成接线SidebarContent为空 — 这是你的工作区域- 页眉中的一个品牌栏位(徽标占位符 + 公司名称)
- 页眉右侧区域中的
ModeToggle和用户菜单
此技能负责填充:
SidebarContent— 根据所选布局填充相应的分区导航- 品牌栏位 — 使用 DOMAIN.md 中的客户徽标和公司名称
- 页眉右侧区域 — 当工作流包含多个角色时,在现有用户菜单前添加角色切换器
DropdownMenu <main>中的<Outlet />— 通过各分区的路由组件进行填充
此技能不会:
- 添加第二个
Sidebar组件。整个应用只有一个侧边栏。 - 在
SidebarContent中放置品牌标识块。品牌标识只放在页眉中。 - 在路由组件中挂载 MainLayout。路由会在
<Outlet />中渲染;布局是父级。在路由中挂载 MainLayout 会导致侧边栏/页眉重复。 - 重新接线
SidebarProvider或替换其可折叠行为。
如果工作流不适合侧边栏布局(见下文的布局模式替代方案),构建时可以使用其他外壳。请在完成摘要中说明这一偏差。
分区模式
默认的 CPQ 工作流包含三个逻辑阶段:配置输入、审核/批准、交付文档。默认 UI 会将这些阶段映射到三个或四个分区,具体取决于用户是否需要单独的“审核/编辑明细行”阶段。
默认分区结构(SMB 直接编辑模式)
对于 SMB CPQ,如果同一角色负责从创建到批准整个报价流程(这是最常见的情况),默认设置为三个分区:
- 编辑报价 — 直接内联编辑所有明细行和客户详情。这是主要工作区,用户约 90% 的时间都会在这里度过。明细行可直接内联添加、编辑和删除。客户信息、条款和备注也都在此内联编辑。实时总额显示在右侧或下方。
- 批准 — 审核并批准。展示最终状态、执行审批前检查,并提供批准操作。如果报价此前已获批准或经过修订,也可以显示变更历史。
- 报价文档 — 最终交付物。只读、可打印,并采用品牌格式。
这将 v4.3 中“配置 → 构建报价”的往返流程合并为一个直接编辑界面。大多数 SMB CPQ 构建都应采用这一三分区模式。
四部分结构(存在角色交接时)
当配置和明细项组装由不同人员完成时(例如:工程师配置 → 销售代表定价 → 经理审批),适合采用四个部分:
- 配置 — 工程师或技术岗位指定产品
- 构建报价 — 销售岗位添加价格、条款和客户信息
- 审批 — 经理审批
- 报价文档 — 最终交付物
仅当 DOMAIN.md 描述了各阶段角色之间真实的交接时,才采用此结构。大多数中小企业的 CPQ 不需要这样做——一个人就能完成配置、构建和审批。使用三个部分。
计算器领域的部分结构
对于计算器/信息收集领域(Clarity Legal 模式):
- 提交详情 — 信息收集表单(面向客户)
- 计算 — 计算得出的结果(根据输入自动生成)
- 律师审核 — 面向审核者的审批(面向律师)
- 最终报告 — 交付的输出
结构模式相同;标签和组件会根据领域进行调整。
偏离情况
当工作流没有审核关卡时,跳过“审批”(自助服务流程)。编辑报价 → 文档。 当交付物不是文档时,跳过“报价文档”(推送到系统、内嵌结果、确认页面)。 当工作流在配置之前有探索阶段时,在“编辑报价”之前添加“探索/信息收集”。 选择与实际工作流相符的部分数量。 不要凑成四个,也不要为了迁就数量而删减。
编辑报价部分 — 直接内联编辑(第 1 级必需)
编辑报价部分以类似 Excel 的行项目表格作为主要工作区。这是产品 CPQ 的硬性要求。
必需行为:
- 每个行项目都是表格中的一行
- 单元格支持内联编辑——点击单元格、编辑数值,总计随之更新
- 通过表格下方的“+ Add Line”按钮添加新行(或在用户点击空白占位行时自动添加)
- 通过行操作菜单(垃圾桶图标、“Remove”选项)删除行
- 通过行操作菜单(“Duplicate”选项)克隆行
- 每行计算总额(数量 × 单价 - 折扣)
- 页脚行计算所有行项目的小计
- 折扣明细显示在小计下方(如适用)
- 税费行显示在折扣下方(如果 DOMAIN.md 提及税费)
- 底部以粗体显示总计
必需列(产品领域):
| # | 描述 | 配置 | 数量 | 标价 | 折扣 | 净价 | 行总额 | 操作 |
|---|
“描述”列显示产品名称。“配置”列显示所选选项(例如“高级套餐 — 50 位用户”或“三色混纺,DTG 印花”)。对于需要配置的产品(捆绑/必需子项模式),点击行会打开配置器抽屉/弹出框,供用户选择选项,然后再提交该行。选定后,配置会内联显示,再次点击即可编辑。
捆绑/必需子项产品的必需行为:
当 DOMAIN.md 描述需要子组件的父产品时——例如“工业设备需要选择电机”、“定制连帽衫需要选择印花方式”、“托管服务合同需要选择套餐”或“狗狗零食订单需要选择包装尺寸”:
- 添加父产品时自动提示用户选择必需的子项
- 行项目显示为一个完整条目:“[Parent Product] — [Required Child] — [Variant]”
- 价格合计为父产品基础价格 + 子项附加费用
- 选择必需子项之前,用户无法保存该行
- 显示可见的规则指示:“[Component name] selection required (BR-001)”
约束规则的必需行为:
当 DOMAIN.md 中存在 requires / excludes / recommends 规则时:
- “Requires”规则会阻止保存,直到满足条件;内联显示“Required: [explanation]”
- “Excludes”规则会阻止无效组合;内联显示“Cannot combine X with Y because [rationale]”
- “Recommends”规则会显示为非强制建议;显示“Customers often add Z with this. Add?”
- 每条规则都显示其规则 ID(BR-001、BR-002),方便用户追溯来源
这种直观的规则执行方式,是从 Excel 切换而来的客户最能感受到“惊艳”的体验之一。请突出展示。
产品配置器模式
当一个产品具有多个配置属性(需要做出 3 个或更多选择),或配置选项会逐级联动(第 1 级选择决定第 2 级选项,第 2 级再决定第 3 级选项,依此类推)时,仅使用单元格内联下拉菜单模式并不足够。用户需要一个真正的配置器。
在许多领域,实际的产品配置通常有 3–4 个层级:
- 工业设备:类型 → 容量 → 电机 → 起重机 → 控制装置
- 定制服装:服装款式 → 面料 → 尺码组合 → 印花/刺绣方式 → 后整理
- IT 服务:服务层级 → 用户数量 → 模块 → SLA 级别 → 集成
- 食品/CPG 批发:产品系列 → 口味或变体 → 包装规格 → 箱装数量 → 冷链/常温配送
- 专业服务:合作类型 → 范围级别 → 团队组成 → 时长 → 交付物格式
- 定制标牌/包装:基材 → 尺寸 → 表面处理 → 印刷方式 → 安装五金件
每个层级都会限制下一级的选项。选择一台 5 吨的工业设备 → 只有某些电机适用 → 只有某些控制装置匹配。选择三混纺连帽衫面料 → 只有某些印花方式兼容 → 只有某些后整理选项。选择 Premium 服务层级 → 解锁某些模块 → 需要更高级别的 SLA。其结构相同。DOMAIN.md 会告诉 Agent 实际配置的内容。
对于这类深度的配置,可根据配置复杂度选择以下三种模式:
模式 A — 内联展开行(2–4 个属性,无级联)
当产品只有少量相互独立的属性(例如数量、颜色、尺寸或一个配置选项)时,行项目会在行内展开以显示这些属性。点击该行 → 展开并显示属性选择器 → 填写属性 → 行收起,并在“配置”列中显示配置摘要。
┌─────────────────────────────────────────────────────────────┐
│ 1 [Product Name] [Variant ▾] 1 $X,XXX.XX ... │ ← collapsed
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 1 [Product Name] [Variant ▾] 1 $X,XXX.XX ... │
│ ┌───────────────────────────────────────────────────┐ │ ← expanded
│ │ Variant: ( ) Option A ( ) Option B │ │
│ │ Quantity: [ 1 ] │ │
│ │ Description: [ ] │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
适用于:
- 总共 2–4 个属性
- 属性相互独立(无级联依赖)
- 展开后所有属性在视觉上都能放入约 200px 的垂直空间内
适合模式 A 的产品示例:包含尺码和颜色的 T 恤、包含工时和费率的服务附加项、软件许可证席位数量、批发箱装数量选择、包含一个后整理选项的印刷横幅。
模式 B — 带垂直步骤指示器的侧边抽屉(4-7 个属性,可包含级联依赖)
当配置存在级联依赖,或包含 4-7 个属性时,点击行后,侧边抽屉会从右侧滑入并覆盖约 40% 的屏幕。抽屉左侧设有垂直步骤指示器,显示各个配置级别。
┌────────────────────────────────┐
│ Configure [Product] │
│ │
│ ●━━━ Step 1: Foundation │
│ │ [Selected value] │
│ │ │
│ ●━━━ Step 2: Sizing │
│ │ [Selected value] │
│ │ │
│ ◉━━━ Step 3: Core Component │
│ │ [ Option A ] [ Option B ] │
│ │ │
│ ○━━━ Step 4: Dependent Choice │
│ │ (Complete Step 3 first) │
│ │ │
│ ○━━━ Step 5: Finishing │
│ │
│ [Cancel] [Save] │
└────────────────────────────────┘
抽屉行为:
- 抽屉内左侧显示垂直步骤指示器(不在主应用侧边栏中)
- 满足依赖条件后,步骤即可点击;未满足时则显示为灰色
- 每个步骤的内容显示在抽屉内步骤指示器的右侧
- 级联依赖:更改上游选项会使下游选项失效并清空(同时显示确认提示:“更改 [上游] 将重置 [下游] 选项”)
- “Save” 会将配置应用到行项目;“Cancel” 会放弃更改
- 行项目会在 Configuration 列中显示组合后的配置摘要
对于确实存在级联依赖的配置,应使用此模式。适合模式 B 的示例:包含类型/容量/电机/控制系统的工业设备,包含服装/面料/印刷方式/后整理的定制服装,包含套餐等级/用户数/模块/SLA 的 IT 服务,以及包含基材/尺寸/印刷/安装方式的定制标牌。抽屉为配置器提供了充足空间,同时不会让用户离开报价工作区。抽屉内的垂直步骤指示器让级联关系一目了然,同时不会占用应用级导航空间。
为什么使用抽屉而非模态框:
- 与模态框相比,抽屉对用户的干扰更小
- 用户仍可将左侧的行项目表作为上下文参考
- 点击外部即可关闭抽屉(避免模态框式的“关闭前先保存”操作阻碍)
- 抽屉与 React Router 配合良好——可作为路由打开,关闭后返回上一级
模式 C — 全页配置器(8 个以上属性,复杂级联)
当配置确实十分复杂——包含 8 个以上属性、多阶段级联,或需要图表、可视化内容时,配置器应使用独立页面。点击“Configure” → 跳转到 /quotes/{id}/lines/{lineId}/configure → 打开全页界面,顶部显示水平步骤指示器,中间为配置主体,右侧为摘要/预览栏。
┌──────────────────────────────────────────────────────────────────┐
│ ← Back to Quote │
│ │
│ ●━━━━━━●━━━━━━●━━━━━━◉━━━━━━○━━━━━━○ │
│ Step 1 Step 2 Step 3 Step 4 Step 5 Review │
│ │
│ ┌─────────────────────────────────────┬──────────────────────┐ │
│ │ │ Selected so far: │ │
│ │ Configuration content for │ │ │
│ │ current step │ Step 1: [value] │ │
│ │ │ Step 2: [value] │ │
│ │ │ Step 3: [value] │ │
│ │ │ Step 4: (selecting) │ │
│ │ │ │ │
│ │ │ Running price: │ │
│ │ │ $X,XXX.XX │ │
│ └─────────────────────────────────────┴──────────────────────┘ │
│ │
│ [Back] [Continue →] │
└──────────────────────────────────────────────────────────────────┘
对于真正复杂的配置,只有全页模式适用。顶部的水平步骤指示器适用于这里(专用的向导式流程),但不适用于报价详情层级——因为在这里,用户确实会一次完成一个步骤,再进入下一步。
适用场景:
- 8 个以上属性
- 配置涉及可视元素(图表、尺寸、照片、色样、布局预览)
- 配置耗时超过 30 秒,值得提供专门的操作界面,让用户专注处理
- 配置结果足够重要,值得设置“确认前审核”步骤
适合模式 C 的示例:包含数十项橱柜、台面、电器和饰面选择的定制厨房;可配置车架、传动系统、车轮、刹车、配件和颜色的自行车;包含模块、用户套餐、集成、支持级别和合同期限的企业软件合同;包含基材、尺寸、结构设计、印刷、后整理、数量和运输方式的定制包装订单。
选择模式
IF product has 2-4 independent attributes, no cascading:
→ Pattern A: Inline expandable row
IF product has 4-7 attributes, cascading dependencies, configuration takes <30s:
→ Pattern B: Side drawer with vertical stepper
IF product has 8+ attributes, visual/diagram component, takes >30s:
→ Pattern C: Full-page configurator with horizontal step indicator
WHEN IN DOUBT:
→ Pattern A for simple-looking products
→ Pattern B for industrial equipment, services with options
→ Pattern C reserved for genuinely complex configurators
级联依赖规则
对于模式 B 和 C,在配置级联时:
- 将下游步骤显示为禁用状态,直到完成上游选择。第 2 步为空时,不要让用户进入第 4 步。
- 当上游选择发生变化时,清除下游选择并显示确认提示:“将产能从 5 吨改为 10 吨会重置电机和起重机的选择。是否继续?”
- 在每一步显示规则依据:“可选电机会根据您选择的 5 吨产能进行筛选(BR-007)。”让筛选规则清晰可见。
- 仅有一个选项时自动选择:如果级联筛选后只剩一个有效选项,则预先选中该选项,并注明“(根据先前选择,这是唯一可用选项)”。
这样能让级联配置显得智能,而不令人困惑。习惯使用 Excel 的客户往往会在心里记着这些规则——“尺寸更大时,就不能使用基础组件”,“选择高级服务层级时,会包含嵌入式支持”,“使用食品级基材时,只能使用水性油墨”——明确展示规则,比默默强制执行更令人印象深刻。
行项目中的配置摘要
配置器完成提交后(抽屉保存、整页确认),行项目会在“配置”列中显示已组装的配置。对于深度为 3–4 层的配置,内容可能很长:
[Industrial equipment example]
Industrial Lift — 5 ton, 40ft span
└─ Standard motor, Type 2 hoist, 480V controls, festoon system
[Custom apparel example]
Premium Hoodie — Tri-blend, M-XL run
└─ DTG print, 4-color front, sleeve embroidery, polybag
[IT services example]
Managed Services — Premium Tier, 50 users
└─ Security module, Backup module, 4-hr SLA, Slack integration
将其显示为简洁的摘要文本,并提供“编辑配置”链接,以重新打开配置器。不要尝试在行项目表格中将每个属性都列为单独的列——属性超过 2–3 个时,这种方式就无法扩展。
参考实现模式:
<table>
<thead>
<tr>
<th>#</th>
<th>Description</th>
<th>Configuration</th>
<th>Qty</th>
<th className="text-right">List Price</th>
<th className="text-right">Discount</th>
<th className="text-right">Net Price</th>
<th className="text-right">Line Total</th>
<th></th>
</tr>
</thead>
<tbody>
{lineItems.map((item, i) => (
<tr key={item.id}>
<td>{i + 1}</td>
<td>
<ProductPicker value={item.productId} onChange={(p) => updateItem(item.id, { productId: p })} />
</td>
<td>
<ConfigurationCell item={item} onChange={(config) => updateItem(item.id, { configuration: config })} />
{item.requiredRules.map(rule => (
<RuleIndicator key={rule.id} rule={rule} satisfied={item.satisfiedRules.includes(rule.id)} />
))}
</td>
<td>
<Input type="number" value={item.qty} onChange={(e) => updateItem(item.id, { qty: e.target.value })} />
</td>
<td className="text-right">{formatCurrency(item.listPrice)}</td>
<td className="text-right">
<DiscountCell item={item} onChange={(d) => updateItem(item.id, { discount: d })} />
</td>
<td className="text-right">{formatCurrency(item.netPrice)}</td>
<td className="text-right font-medium">{formatCurrency(item.lineTotal)}</td>
<td>
<RowActions onClone={() => cloneItem(item.id)} onRemove={() => removeItem(item.id)} />
</td>
</tr>
))}
</tbody>
<tfoot>
<tr><td colSpan={7} className="text-right">Subtotal:</td><td className="text-right">{formatCurrency(subtotal)}</td><td /></tr>
{discountRows.map(d => (
<tr key={d.id}><td colSpan={7} className="text-right text-muted-foreground">{d.label}:</td><td className="text-right">-{formatCurrency(d.amount)}</td><td /></tr>
))}
{taxRate > 0 && (
<tr><td colSpan={7} className="text-right">{taxName} ({taxRate}%):</td><td className="text-right">{formatCurrency(taxAmount)}</td><td /></tr>
)}
<tr className="font-bold text-lg"><td colSpan={7} className="text-right">Total:</td><td className="text-right">{formatCurrency(grandTotal)} {currency}</td><td /></tr>
</tfoot>
</table>
<Button onClick={addNewLine}>+ Add Line</Button>
客户信息、付款条款、有效期和备注显示在行项目表格下方的一个区域中——直接显示在同一页面上,而不是作为单独的路由或步骤。
折扣叠加模式(应用折扣时 Tier 1 必须支持)
当 DOMAIN.md 提及任何形式的折扣(批量、促销、手动、协商)时,构建的原型必须将折扣显示为分层且透明的计算结果。
必须显示的计算:
List Price (5 × $15,000): $75,000.00
─────────────────────────────────────────
Volume Discount (5%): -$3,750.00
Promotional Discount (3%): -$2,137.50
Manual Discount ($1,000): -$1,000.00
─────────────────────────────────────────
Net Price: $68,112.50
HST (13%): $8,854.63
─────────────────────────────────────────
Total: $76,967.13 CAD
必须实现的行为:
- 汇总区域中的每项折扣单独占一行
- 每行显示:折扣类型、百分比或金额、扣除的金额
- 折扣按叠加顺序应用(批量 → 促销 → 手动)
- 手动折扣超过 DOMAIN.md 中的阈值时,触发审批流程
- 用户可以看到扣除了什么以及原因;公式中不得隐藏任何信息
折扣审批阈值:
当 DOMAIN.md 描述折扣审批规则(“超过 15% 的折扣需要经理审批”)时,原型必须强制执行这些规则:
- 折扣低于阈值 → 用户可以直接应用,无需审批
- 折扣达到或超过阈值 → 用户可以应用,但报价状态会变为“待审批”
- 审批流程会将请求发送给有权审批该折扣级别的角色
这是 SMB 企业最常见的“我们利润率下降了”抱怨。在界面中展示规则能带来很高的价值。
多级审批链模式(Tier 1 必须支持)
大多数 SMB CPQ 工作流有 2 个或更多审批级别。原型必须体现这一点。
审批链定义
DOMAIN.md 会在利益相关者映射中描述审批人。原型根据该映射得出审批链:
- 单个审批人 → 简单关卡(“等待 [Owner] 审批”)
- 顺序审批人 → 审批链(“等待 [Sales Manager] 审批,然后等待 [Owner] 审批”)
- 条件审批人 → 根据报价属性进行路由(“标准配置路由至 [Reviewer A],服务请求路由至 [Reviewer B],维护请求路由至 [Reviewer C]”)
审批链 UI
清晰展示审批链,让用户了解报价目前处于哪个环节,以及接下来会发生什么:
Quote Status: Pending Approval
─────────────────────────────────────────
✓ Submitted by [Sales Rep] (May 5, 2:30 PM)
✓ Approved by [Sales Manager] (May 5, 3:15 PM)
○ Pending approval from [Finance Lead]
○ Pending final signoff from [Owner]
每位审批人:
- 都能在自己的队列中看到报价(筛选列表视图:“等待我审批”)
- 可以批准、拒绝或请求修改
- 其操作会推进或中止审批链
- 被拒绝或要求修改的报价会连同备注一起返回给上一位审批人
构建时的要求:
- 审批链根据 DOMAIN.md 的 Stakeholder Map 自动生成
- 角色切换器允许用户切换为任意审批人,查看其队列
- 多报价列表中的“等待我审批”筛选器会显示待当前角色审批的报价
- 审批操作会更新审批链状态,并触发 Toast 确认提示
- 拒绝或要求修改时,需要填写评论,且下一位或上一位角色可以看到该评论
审批路由规则
如果 DOMAIN.md 描述了路由规则——例如,“将维护请求路由给服务经理,将巡检请求路由给现场主管”——原型就应实现这些路由。逻辑示例(DOMAIN.md 会替换占位名称):
// Example routing logic derived from DOMAIN.md stakeholder map:
// - Standard quotes: route to [Sales Manager]
// - Inspection requests: route to [Field Supervisor]
// - Maintenance requests: route to [Service Manager]
// - All quotes finalized by [Owner]
function getApprovalChain(quote) {
const chain = [];
if (quote.requestType === 'inspection') {
chain.push({ role: 'inspection-reviewer', name: '[Field Supervisor]' });
} else if (quote.requestType === 'maintenance') {
chain.push({ role: 'maintenance-reviewer', name: '[Service Manager]' });
} else {
chain.push({ role: 'sales-reviewer', name: '[Sales Manager]' });
}
chain.push({ role: 'final-approver', name: '[Owner]' }); // Always final-signoff at end
return chain;
}
在实际构建中,请将占位名称替换为 DOMAIN.md 的 Stakeholder Map 中的真实名称。原型会在“审批”部分明确显示审批链,让用户了解路由逻辑。这是对 SMB 客户最有价值的功能之一——他们此前从未使用过自动路由。
布局模式
默认布局为列表/详情,因为 SMB CPQ 用户通常会同时处理多个报价。他们需要查看队列并深入查看单个报价。
默认:列表/详情布局
+----------+--------------------------------+
| | [List of quotes] |
| Filters | row (status badge) |
| Quick | row |
| filters | row |
| | |
| | + New Quote |
+----------+--------------------------------+
用户点击某个报价后,会跳转到详情路由:
+--------------------------------------------------------------+
| Header: [Company Name] | Q-2026-0001 | Status: Draft |
| ← All Quotes |
+--------------------------------------------------------------+
| [Edit Quote] [Approve] [Quote Document] tabs |
| ──────────────────────────────────────────────────────────── |
| |
| [Active section content — line items table by default] |
| |
| [Live totals on right or below — collapsible] |
+--------------------------------------------------------------+
列表/详情布局为何是默认选择:
- 客户使用 Excel 时,会为不同报价创建多个工作表/文件
- 他们需要一目了然地查看所有正在处理的报价(队列视图)
- 他们需要按状态、客户、审批人和日期筛选
- 深入查看某个报价时不应丢失队列上下文(返回按钮始终可用)
- 审批队列本质上就是列表(“显示所有等待我审批的项目”)
**列表视图中的侧边栏:**筛选器、角色切换器、已保存报价的快捷入口,以及“+ 新建报价”链接。不要放入工作流步骤指示器(此时尚未打开任何报价)。
**详情视图中的侧边栏:**四部分/三部分导航(编辑报价 / 审批 / 报价文档)。也可以在详情视图中使用顶部标签页代替侧边栏——两种方式都可以;根据视觉密度选择。
**右侧栏/实时摘要:**可折叠。在“编辑报价”中默认展开(总额是重要的上下文信息)。在“报价文档”中默认折叠(文档本身就是摘要)。
备选:单报价布局
当 DOMAIN.md 描述的工作流中,用户始终一次只处理一个报价时(CPQ 中较少见,但某些计算器场景适用),使用不含列表视图的单页布局。报价本身就是页面。
备选:计算器式布局(计算器领域)
对于以计算为主要功能的计算器/信息收集领域:
+--------------------------------------------------------------+
| [Single-column form] |
| |
| Personal details |
| [field rows] |
| |
| Financial details |
| [field rows] |
| |
| ───────────────────────────────────── |
| |
| Calculated result |
| [inline output panel — updates as user types] |
| |
| [Submit for review] |
+--------------------------------------------------------------+
Clarity Legal 面向客户的流程采用此布局。面向律师的审核流程采用列表/详情布局。
布局决策规则
IF the user manages multiple in-flight workflows in parallel (almost all CPQ):
→ List/Detail layout (DEFAULT)
IF the calculation is the primary feature AND can be shown inline with inputs:
→ Calculator-Style layout
IF the user only ever works on one item at a time (rare):
→ Single-Page layout
IF in doubt:
→ List/Detail layout
侧边栏行为
使用列表/详情布局时,侧边栏会根据用户当前处于列表视图还是详情视图而变化:
**列表视图:**筛选器、角色切换器、“+ 新建报价”按钮,以及可选的已保存筛选器快捷入口。
**详情视图:**分区导航(编辑报价 → 审批 → 报价文档),顶部提供返回列表的链接。
两种视图都使用 SidebarContent——根据路由切换内容,不要添加第二个侧边栏。这是常见的实现错误:Agent 在详情路由中挂载 MainLayout,导致侧边栏重复。不要这样做。
右侧栏可折叠
报价摘要面板是可折叠的右侧边栏,而不是固定面板。使用 shadcn 的 Sidebar 组件并设置 side="right",或使用 Sheet 实现画布外行为。
各区域的默认状态:
- 编辑报价:展开(总计金额至关重要)
- 审批:展开(最终审核需要上下文)
- 报价文档:折叠(文档就是摘要)
用户可以随时通过标题栏中的触发按钮切换状态。
报价生命周期指示器
用户进入报价详情视图后,需要了解当前报价处于生命周期的哪个阶段,以及如何在不同视图(编辑、文档、审批)之间切换。
这是两个不同的问题,需要分别提供两种交互方式。
问题 1 — 工作流状态(“这份报价处于生命周期的哪个阶段?”)
报价会经历以下状态:草稿 → 等待审批 → 已批准 → 已发送(或已拒绝)。用户需要始终看到当前状态。
默认模式:在页面标题附近显示状态徽章。
在报价编号旁放置一个 Badge,显示当前状态。根据状态使用不同颜色:
- 草稿 → 轮廓样式 / 灰色
- 等待审批 → 默认样式 / 琥珀色
- 已批准 → 次要样式 / 绿色
- 已拒绝 → destructive / 红色
- 已发送 / 已定稿 → 次要样式 / 蓝色
这是最低要求。v4.5 版本中已包含此功能,且效果良好。
可选增强:水平状态流程。
对于包含 4 个或更多可见状态,且客户能从一目了然的进度中受益的工作流,可在页面标题下方添加水平状态行:
●━━━━━━━━━━━━━●━━━━━━━━━━━━━◉━━━━━━━━━━━━━○━━━━━━━━━━━━━○
Draft [Reviewer] [Approver] Approved Sent
(complete) (complete) (current)
已完成的状态使用实心圆表示,当前状态使用带填充的空心圆表示,未来状态使用空心圆表示。在等待审批的阶段显示审批人姓名,让用户知道报价目前由谁处理。
如果生命周期较简单(不超过 3 个状态),则无需采用此方式,状态徽章已足够。添加 3 步状态流程只是装饰,并没有提供更多信息。
问题 2 — 视图导航(“如何在编辑视图和文档视图之间切换?”)
用户需要在可编辑的工作区、只读的客户文档视图以及其他视图(审批队列、历史记录)之间切换。这些是同一份报价的并列视图,而非连续阶段。
默认模式:在详情页顶部放置标签页。
将 Tabs 放在页面标题下方和主要内容区域上方:
[Edit Quote] [Document] [Approval] [History]
═══════════
当前标签页使用下划线或填充样式。未选中的标签页可以点击。这种模式最合适,因为:
- 标签页表示“并列视图”——不会暗示先后顺序
- 只需单击即可切换,无需弹出模态框或跳转页面
- 每个标签页都可以显示数量或状态徽章(“审批(1 项待处理)”、“历史记录(5 项)”)
- 禁用状态有明确含义——在存在明细项之前,可以禁用“文档”
- 可以轻松扩展至 6 个标签页;如果超过 6 个,说明工作流可能包含过多阶段
标签页可用性规则:
- 编辑 — 始终可用
- 文档 — 至少存在一个明细项后才可用(否则文档为空)
- 审批 — 仅当报价处于审批状态或存在审批历史时显示
- 历史记录 — 报价发生过任何状态变更(编辑、批准、拒绝)时显示
不要显示空标签页。不要显示“即将推出”的标签页。
何时不使用选项卡——改用垂直步骤条
适合使用垂直步骤条(左侧栏中的编号步骤,类似 v4.3 构建版本)的情况:
- 工作流包含 4 个或更多真正按顺序执行的步骤,不能跳过顺序
- 用户会 逐一完成每个步骤,再进入下一步(这是向导,而不是工作区)
- 工作流 有明确的结束点——用户完成第 N 步后,报价即告完成
大多数 CPQ 都不符合这些条件。报价是工作区——用户会反复查看、编辑,也会稍后再回来。选项卡符合这种心智模型。在应用级别使用垂直步骤条,会把向导式心智模型强加给工作区工作流,还会产生视觉问题(步骤标签被挤压、侧边栏空间利用不当)。此技能的早期版本曾犯过这个错误;当前模式将垂直步骤条仅用于配置器抽屉,而不用于应用外壳。
垂直步骤条应留给真正的向导:入门流程、一次性设置,或由不同人员负责各阶段的企业多阶段交易。
何时既不使用选项卡,也不使用步骤条——只用面包屑
面包屑显示层级和位置,而不是工作流阶段。用户沿着 树形结构向下导航(Quotes › Q-2026-0007 › Line Items)时使用面包屑,但不要用它代替阶段导航。
实际上,两者可以共存:最顶部的面包屑显示当前位置,下方的选项卡显示当前项目的同级视图。
工作流简单到不需要这些模式时
有些工作流只有一个界面(计算器式单页布局)。不需要选项卡。页面本身就是工作区。仅靠状态徽章即可传达状态。用户需要时,报价文档会在单独的路由或模态框中打开。
不要为了填满布局而添加选项卡栏。如果只有一个选项卡,那就没有选项卡。
总结
| 工作流形态 | 模式 |
|---|---|
| 多视图工作区(Edit/Document/Approval) | 详情页顶部使用 选项卡 + 标题附近的状态徽章 |
| 多视图工作区 + 复杂生命周期(4 个或更多状态) | 选项卡 + 状态徽章 + 水平状态流程行 |
| 按顺序执行步骤的真正向导 | 左侧栏中的 垂直步骤条 |
| 层级导航 | 面包屑(如果也存在同级视图,则与选项卡搭配使用) |
| 单页工作流 | 仅使用 状态徽章 |
大多数产品类 CPQ 使用第 1 行模式——多视图工作区。Edit/Document/Approval 使用选项卡,标题附近显示状态徽章。
报价文档(最终输出)
这是交付成果。对于产品领域,这是面向客户的报价 PDF;对于计算器领域,这是汇总报告。
应将其视为真正的文档,而不是摘要卡片。**质量标准:**如果你会不好意思把它作为“报价/报告”发给客户,那它就还没有完成。
布局(从上到下)
1. 文档页眉 — 两列:
- 左侧:品牌徽标(发生错误时回退到带色调的首字母方块 — 切勿使用裸露的 img 标签)。公司名称。公司地址。
- 右侧:文档标题(“报价单”“估算单”“汇总报告”等)。参考编号(自动生成,例如“Q-2026-0001”)。文档日期。适用时填写有效期。
2. 接收方信息块 — 接收方姓名、联系邮箱、客户公司。突出显示。
3. 内容块:
产品领域:行项目表格。 | # | 描述 | 配置 | 数量 | 单价 | 行总计 |
计算器领域:输入表格 + 结果表格。(参见 Clarity Legal 模式。)
4. 总计/摘要块:
产品领域 — 右对齐的总计项,并完整展示折扣计算:
Subtotal: $75,000.00
Volume Discount (5%): -$3,750.00
Promotional Discount (3%): -$2,137.50
─────────────────────────────────────
Net Subtotal: $69,112.50
HST (13%): $8,984.63
─────────────────────────────────────
Total: $78,097.13 CAD
计算器领域 — 突出显示主要计算值或数值范围。对于范围,三卡片布局(低/中/高)并突出主要数值效果很好。
5. 条款/免责声明块:
产品:付款条款、币种、有效期。 计算器:DOMAIN.md 中的强制法律/监管免责声明。
6. 审批流程块 — 显示审批历史:
Approved by:
✓ [Reviewer Name] (Sales Manager) — May 5, 2026
✓ [Reviewer Name] (Finance) — May 6, 2026
✓ [Reviewer Name] (Owner) — May 6, 2026
这会让客户印象深刻 — 证明报价单经过了适当的审批流程。
7. 状态徽标 — 草稿 / 等待审核 / 已批准 / 已定稿。清晰可见。
8. 页脚 — 小字说明、联系信息,以及领域要求的签名栏。
只读
文档视图中不提供编辑控件。仅可执行以下操作:“返回编辑报价单”、“打印”、“下载 PDF”(原型中为带提示消息的占位操作)。
RBAC 行为
当工作流包含多个角色时:
- 使用 DOMAIN.md 的“用户角色”或“利益相关方映射”中的角色填充 localStorage
- 角色切换器是页眉中的单个
DropdownMenu。触发器中显示当前角色 + 徽标 - 视图限制: 不同角色默认看到不同的列表筛选条件(审批者看到“待我审批”;准备者看到“我的草稿”)
- 操作限制: 只有获授权的角色才会看到审批按钮
- 字段限制: 非审批者角色看不到敏感数字(成本、利润率)
- 路由可见性: 当某个角色负责特定工作类型时,在该角色处于活动状态时显示相关路由信息
当 DOMAIN.md 仅描述一个角色或未描述角色时,省略角色切换器。不要为了填充 UI 而编造角色。
角色无权操作时,应采用以操作为导向的提示:
- ❌ 禁用按钮(令人困惑 — 用户不知道原因)
- ✓ “切换到[审批者角色]角色以[执行操作]”(用于带角色切换器的原型)
- ✓ “此操作需要[审批者角色]权限。请联系[name]以获取批准。”(用于生产环境)
shadcn/ui 组件映射
使用这些 shadcn/ui 组件。从 ~/components/ui/* 导入。卡片应视为例外,而非默认选择——视觉质量标准请参阅 frontend-design skill。
| CPQ 元素 | 组件 | 备注 |
|---|---|---|
| 行项目表格 | 带有 TableHeader、TableBody、TableFooter 的 Table | 单元格可内联编辑。TableFooter 用于汇总金额。 |
| 可编辑单元格(数字) | Input type="number" | 在单元格内占满宽度。失焦或值变更时更新。 |
| 可编辑单元格(选择项) | Select | 用于表格单元格中的下拉菜单。 |
| 配置单元格 | 自定义弹出框/抽屉 | 点击打开配置器,并在单元格内显示摘要。 |
| 行操作 | DropdownMenu | 以垃圾桶图标为触发按钮,选项:编辑 / 复制 / 移除。 |
| 添加行按钮 | Button variant="outline" | 位于表格下方。添加空白行或打开选择器。 |
| 状态徽标 | Badge | outline 表示草稿,default 表示待处理,secondary 表示已批准。 |
| 角色切换器 | DropdownMenu | 位于页眉。显示当前角色和徽标。 |
| 右侧边栏(可折叠) | Sidebar side="right" | 也可使用 Sheet 实现画布外面板。从页眉切换。 |
| 审批链展示 | 带状态图标的自定义列表 | 逐步展示,并使用勾选标记/待处理圆圈。 |
| 报价列表 | Table 或行列表 | 在上方显示状态筛选标签。点击行 → 详情路由。 |
| 筛选器 | 标签组 / Select | 位于报价列表上方。按状态、客户、审批人筛选。 |
| 确认对话框 | AlertDialog | 用于破坏性操作(删除、拒绝)。 |
| Toast 通知 | Sonner / toast() | 保存、批准、拒绝、克隆后显示。 |
| 报价文档 | 打印样式文章 | print:border-0,品牌页眉,汇总金额。 |
| 汇总中的折扣行 | 内联标签/值 | 折扣行使用弱化颜色。 |
配置架构
完整的 TypeScript 接口请参阅 references/config-schema.md。摘要:
config
├── app ← Branding, theme
├── sections[] ← Sections (3 default for SMB direct-editing)
├── layout ← list-detail | calculator-style | single-page
├── data
│ ├── products[] ← Catalog with options, required-children
│ ├── inputSections[] ← Calculator domain inputs
│ ├── quotes[] ← All quotes (multi-quote management)
│ └── quoteSettings ← Currency, tax, terms, markup
├── rules[] ← Constraint rules + business rules + discount rules
├── approvalChain ← Multi-tier approval routing
└── roles[] ← Roles with permissions and view filters
确定性映射规则
领域类型检测
INSPECT DOMAIN.md:
IF Entity Registry has products with prices/options/accessories:
→ DOMAIN TYPE: product
ELSE IF Entity Registry has input fields with rules and DOMAIN.md has guidelines/formulas:
→ DOMAIN TYPE: calculator
ELSE IF both:
→ DOMAIN TYPE: hybrid (rare — pick dominant)
ELSE:
→ AMBIGUOUS — note in completion summary, default to product
区块数量决策
EVALUATE workflow handoffs:
IF same role does configure + line management + approval:
→ 3 sections: Edit Quote, Approve, Quote Document (DEFAULT for SMB)
IF different roles for configure vs line management:
→ 4 sections: Configure, Build Quote, Approve, Quote Document
IF no review gate exists:
→ Skip Approve section
IF deliverable isn't a document:
→ Replace Quote Document with appropriate output (confirmation, push-to-system, inline result)
布局决策
PICK based on workflow:
IF user manages multiple quotes in parallel (almost all CPQ):
→ List/Detail layout (DEFAULT)
IF calculation is primary feature, simple inputs/outputs:
→ Calculator-Style layout
IF single-item workflow (rare):
→ Single-Page layout
实体 → 可配置项目映射
FOR EACH entity in DOMAIN.md Entity Registry:
PRODUCT DOMAIN:
WHERE entity is sellable product/service/part:
→ CREATE config.data.products[] entry
→ SET id, name, category, basePrice, pricingSource
→ SET options[] from entity's "what varies" attributes
→ SET requiredChildren[] from "must include" relationships (e.g., crane requires motor)
→ SET optionalChildren[] from "may include" relationships
CALCULATOR DOMAIN:
WHERE entity is input field/parameter:
→ CREATE config.data.inputSections[] entry
→ GROUP related inputs into sections
→ SET field id, label, type, required, validation
关系 → 规则映射
FOR EACH relationship:
"requires" → config.rules[] (type: requires, severity: error, surface visibly)
"recommends" → config.rules[] (type: recommends, severity: info, surface as suggestion)
"excludes" → config.rules[] (type: excludes, severity: error, block invalid combo)
"includes child" → config.products[].requiredChildren[] (bundle pattern)
折扣汇总映射
FOR EACH discount type in DOMAIN.md:
→ CREATE config.data.discountTypes[] entry
→ SET id, label, type (percentage|amount), rate, conditions
→ IF discount has approval threshold:
→ CREATE config.rules[] entry (type: approval-required, threshold: X)
EXAMPLES:
"5% volume discount over 10 units" → percentage discount with quantity condition
"Promotional 3% in Q4" → percentage discount with date condition
"Discounts over 15% require manager approval" → approval-required rule, threshold 0.15
审批链映射
FROM DOMAIN.md Stakeholder Map and routing rules:
→ CREATE config.approvalChain entry per quote type
→ IF routing rules exist (e.g., "inspections to Dre, maintenance to Manish"):
→ CREATE conditional routing in approvalChain
→ ALWAYS append final approver if DOMAIN.md describes one
→ SURFACE the chain visually in the Approve section
状态模型 → 工作流映射
IF DOMAIN.md State Models contain workflow statuses:
→ MAP to quote.status enum (Draft, Awaiting Approval, Approved, Rejected, Finalized)
→ MAP transitions to action availability
品牌 → 主题映射
→ SET config.app.companyName from DOMAIN.md Project Overview
→ SET config.app.theme.primaryColor from brandfetch
→ SET config.app.theme.accentColor from brandfetch
→ SET config.app.theme.logoUrl from brandfetch (with onError fallback in BrandMark)
→ SET config.app.theme.mode = "light"
报价设置映射
Product domain:
→ SET currency, taxEnabled (only if DOMAIN.md mentions tax), taxLabel, taxRate
→ SET defaultTerms, markup, quoteFormat
Calculator domain:
→ SET formulas from DOMAIN.md guidelines
→ SET outputFormat per deliverable type
→ SET disclaimers from DOMAIN.md mandatory text
角色映射
FOR EACH role in DOMAIN.md User Roles:
→ CREATE config.roles[] entry
→ SET id, label, permissions, viewFilters, fieldVisibility
→ IF role appears in approval chain → mark as approver
→ IF only one role or no roles → omit role switcher in UI
边缘情况
→ IF entity has no price → SET pricingSource = "tbd", ADD to openQuestions
→ IF relationship rationale missing → SET message = "[source] [rel] [target] — rationale not captured"
→ IF entity unclassifiable → SKIP, ADD to openQuestions
→ IF DOMAIN.md has Open Questions → COPY to config.metadata.openQuestions
→ IF only one role → CREATE default role, OMIT role switcher
→ IF no pricing AND domain is product → SET markup = 0, ADD to openQuestions
→ IF no calculation formulas AND domain is calculator → BUILD with placeholder formulas, ADD to openQuestions
→ IF DOMAIN.md mentions discounts but no approval thresholds → use 15% default for "requires approval"
业务规则模板
产品依赖(硬性要求)
{
"id": "BR-XXX",
"type": "requires",
"trigger": "addItem",
"condition": { "item.category": "[source_category]" },
"action": { "suggest": "[target_product_id]", "matchField": "[matching_attribute]" },
"message": "[rationale from DOMAIN.md]",
"severity": "error",
"surfaceVisibly": true
}
产品推荐(软性建议)
{
"id": "BR-XXX",
"type": "recommends",
"trigger": "addItem",
"condition": { "item.category": "[source_category]" },
"action": { "suggest": "[target_product_id]" },
"message": "[rationale from DOMAIN.md]",
"severity": "info",
"surfaceVisibly": true
}
产品排除
{
"id": "BR-XXX",
"type": "excludes",
"trigger": "addItem",
"condition": { "item.category": "[source_category]" },
"action": { "block": "[target_product_id]" },
"message": "[rationale from DOMAIN.md]",
"severity": "error",
"surfaceVisibly": true
}
套装 / 必选子项
{
"id": "BR-XXX",
"type": "requires-child",
"parent": "[parent_product_id]",
"child": "[child_product_id_or_category]",
"selectionMode": "required-one-of",
"message": "[rationale]",
"severity": "error"
}
折扣阈值审批关卡
{
"id": "BR-XXX",
"type": "approval-required",
"trigger": "discountApplied",
"condition": { "discount.percentage": { "$gte": 0.15 } },
"action": { "requireApproval": "[approver_role_id]" },
"message": "Discounts over 15% require [approver name] approval",
"severity": "warning"
}
多级审批链
{
"id": "BR-XXX",
"type": "approval-chain",
"trigger": "submitForApproval",
"chain": [
{ "role": "sales-reviewer", "name": "[Sales Manager]", "condition": { "quote.requestType": "standard" } },
{ "role": "inspection-reviewer", "name": "[Field Supervisor]", "condition": { "quote.requestType": "inspection" } },
{ "role": "maintenance-reviewer", "name": "[Service Manager]", "condition": { "quote.requestType": "maintenance" } },
{ "role": "final-approver", "name": "[Owner]" }
],
"message": "Routed through reviewer based on request type, finalized by [Owner]"
}
在实际配置中,将占位名称替换为 DOMAIN.md 的 Stakeholder Map 中的真实名称。
计算器公式
{
"id": "BR-XXX",
"type": "computes",
"trigger": "inputChange",
"condition": { "fields": ["incomeA", "incomeB", "duration"] },
"action": { "compute": "supportLow = (incomeB - incomeA) * 0.015 * yearsOfMarriage" },
"message": "[formula basis from DOMAIN.md]",
"severity": "info"
}
垂直行业预设
| 垂直行业 | 领域类型 | 常见布局 | 关键 Tier 1 功能 |
|---|---|---|---|
| 制造业 / BOM | 产品 | 列表/详情 | 套装(父项 + 配件)、折扣汇总、多级审批 |
| 批发 / 分销 | 产品 | 列表/详情 | 数量阶梯(Tier 2)、折扣汇总、客户定价 |
| 服务 / 集成商 | 产品 | 列表/详情 | 设备 + 人工 + 材料套装、审批链 |
| 法律 / 合规 | 计算器 | 计算器样式 + 列表/详情 | 公式计算、强制免责声明、律师审核队列 |
| 金融 / 保险 | 计算器 | 计算器样式 + 列表/详情 | 费率表、资格规则、范围输出 |
| 评估 / 资格判定 | 计算器 | 计算器样式 | 评分模型、阈值规则、建议输出 |
完成前验证
完成构建前,请确认满足所有 Tier 1 标准:
[ ] Direct inline editing — line items table with editable cells, no Configure-then-Build round trip
[ ] Bundle / required-child — parent products with required children handled in single line; configurator pattern matches complexity (inline / drawer / full-page)
[ ] Constraint rules visible — requires/excludes/recommends surfaced with rationale and rule IDs
[ ] Discount stack — visible math, layered calculation, no hidden formulas
[ ] Live quote summary — totals update in real-time as user edits
[ ] Branded quote document — logo, line items, totals, terms, approval chain, professional print layout
[ ] Multi-tier approval routing — chain derived from DOMAIN.md, surfaced visually
[ ] Multi-quote management — list view with filters, drill into detail
[ ] Save / load / clone — all persisted to localStorage
[ ] Role-based gating — view filters, action gating, sensitive field hiding
[ ] Quote lifecycle indicator — tabs for view navigation + status badge for state; horizontal status flow when 4+ states
如果缺少任何 Tier 1 标准,则构建尚未完成。请先修复再完成。
[ ] No duplicate sidebars — verify by routing through to detail view, count Sidebar components (should be 1)
[ ] No mounted MainLayout inside route — routes render in <Outlet />
[ ] Light mode set in BOTH app.css AND ThemeProvider default
[ ] BrandMark component used everywhere a logo appears (no bare <img>)
[ ] Currency uses Intl.NumberFormat with thousands separators
[ ] Footer text appears once, not duplicated by layout nesting
这些是常见的实现错误,虽然能通过 npm run build,却会破坏用户体验。
映射日志
执行映射规则后,生成映射日志:
## Mapping Log
**Skill:** cpq-builder v4.7
**DOMAIN.md:** [company name]
**Domain type:** [product / calculator / hybrid / ambiguous]
**Vertical preset:** [manufacturing / wholesale / services / legal / financial / assessment / none]
**Section count:** [3 / 4 / 5] (deviations: [list])
**Layout:** [list-detail / calculator-style / single-page]
### Tier 1 standards: [all met / list any gaps]
- [confirm or note gap]
### Tier 2 capabilities built: [N]
- [list with rationale]
### Tier 3 capabilities mentioned in completion summary: [N]
- [list]
### Items mapped: [N]
- [entity name] → config.data.products[0] (with [N] required children, [N] options)
### Rules mapped: [N]
- BR-001: [source] [rel] [target] → [severity, action]
### Approval chain configured:
- [chain description]
### Discount stack configured:
- [list discount types and thresholds]
### Configurator pattern used:
- [inline-expand / drawer-with-stepper / full-page] — [rationale based on attribute count and cascading]
### Lifecycle indicator pattern:
- Tabs: [Edit / Document / Approval / History — list which are present]
- Status flow: [included / omitted — rationale]
### Skipped entities: [N]
- [entity name] — [reason]
### Open questions carried forward: [N]
- [question from DOMAIN.md]
参考文件
references/config-schema.md— CPQ 配置结构的完整 TypeScript 接口references/vertical-presets.md— 产品和计算器领域的详细预设references/example-config.json— 完整填充的示例配置