如何开发ERP(离散制造-MTO)系统中的客户管理板块(附架构图+流程图+代码参考)

简介: 本文详解离散制造-MTO模式下ERP系统客户管理模块的设计与实现,涵盖架构图、流程图、功能拆解、开发技巧及TypeScript参考代码,助力企业打通客户信息与报价、生产、交付全链路,提升响应效率与订单准交率。

在离散制造-MTO(Make-To-Order,按订单生产)的场景下,客户就是制造的起点。客户信息、跟进记录和客户分析直接决定报价准度、交期管理、产能排产和资金回笼效率。很多企业把ERP的“客户管理”当成CRM的简单复制,但在MTO场景里它需要更紧密地和BOM、工艺路线、报价模块、订单、交付与售后衔接。本文将给出一套可实施的客户管理模块设计(包含架构图、流程图、功能拆解、开发技巧、以及一个较大的参考代码),帮助企业快速搭建或改造适配离散制造-MTO的客户管理板块。


本文你将了解

  1. 概念与必要性:什么是ERP(离散制造-MTO)系统?为什么要在ERP里做客户管理?
  2. 客户管理在MTO中的定位与目标(客户、跟进记录、客户分析)
  3. 整体架构设计(含架构图)
  4. 详细功能模块与业务流程
  5. 开发详解与实现技巧(表设计、索引、接口、权限、审计、缓存、并发)
  6. 参考代码
  7. 实现效果与交付验收建议

注:本文示例所用方案模板:简道云ERP系统,给大家示例的是一些通用的功能和模块,都是支持自定义修改的,你可以根据自己的需求修改里面的功能。


1. 概念与必要性

什么是 ERP(离散制造-MTO)系统? 简要说:ERP 是企业资源计划系统。离散制造指产品是离散的(零部件、装配件),MTO 表示多数生产是按订单生产而非库存生产。MTO 最大的挑战是订单多变、每单可能不同(BOM、交期、工序不同),因此前端的客户信息和跟进记录直接影响制造端决策。

为什么要在 ERP 里做客户管理而不是单独用 CRM? 因为在 MTO 场景下:客户的需求常常牵涉到工艺、BOM、报价与交期。把客户管理放在 ERP,能实现客户信息与报价、销售订单、生产排程、采购需求的无缝联动,减少信息孤岛与重复录入,提升响应速度与准交率。


2. 客户管理在 MTO 中的定位与目标

核心要解决的问题:

  • 快速、准确地拿到客户需求(产品/规格/交期/价格敏感度)并能追溯历史沟通(跟进记录)。
  • 把客户分层(重点客户/战略客户/低频客户),自动化提示跟进、促单或流失预警。
  • 提供面向业务的分析(下单周期、单均金额、转化率、流失率),支持报价策略和产能保障决策。

关键功能围绕三大对象:客户(Customer)跟进记录(FollowUp)客户分析(Analysis)


3. 整体架构设计(文字 + 架构图 —— Mermaid)

下面给出一个典型的模块化架构(微服务或单体模块化均可适配):

graph TD

 A[前端应用:销售/客服/售后] -->|REST/GraphQL| B[API 网关 / 后端服务]

 B --> C[客户管理服务]

 C --> D[(数据库:Customer, FollowUp, Tags, Events)]

 C --> E[分析服务 / OLAP层]

 B --> F[订单服务]

 B --> G[报价服务]

 B --> H[生产排程服务]

 E --> I[BI / 报表 & 告警]

 C --> J[消息队列(通知/提醒/钉钉/邮件)]

 subgraph ThirdParty

   K[外部CRM/线索系统] -->|同步 / 导入| B

   L[电话/邮件系统] -->|Webhook| C

 end

说明:客户管理处在 ERP 的核心位置,需要与订单、报价、生产排程和外部通信系统互通,另外提供向分析服务输出维度化数据以支持 BI 报表和预警。


4. 功能拆解与业务流程(含流程图)

总体客户生命周期流程:线索 → 客户建立 → 跟进(多轮)→ 报价/试产 → 下单 → 交付 → 售后/回访 → 留存或流失。

下面是流程图(Mermaid):

flowchart TD

 Lead[线索/客户线索] -->|验证| CustCreate[建立客户档案]

 CustCreate --> Follow[跟进记录(多次)]

 Follow -->|需求确认| Quote[报价/评审]

 Quote -->|通过| SO[销售订单]

 SO --> Prod[生产排程]

 Prod --> Delivery[交付]

 Delivery --> AfterSale[售后/回访]

 AfterSale -->|满意| Retain[留存]

 AfterSale -->|不满意| Churn[流失/降级]

4.1 客户主档(Customer)

必有字段(最小集):

  • id, name, short_name, type(经销/直客), industry, area, 联系人列表(联系人表)、默认结算条款、信用等级、付款方式、结算周期、税号、开户行、状态(active/inactive/潜在) 建议字段:签约日期、客户来源、客户负责人(销售 id)、优先级标签、最近下单时间、累计下单金额、SKU 多样性指标。

设计要点:

  • 联系人单独建表(support 多联系人、多渠道)。
  • 客户与公司业务一一绑定或多绑定(多组织/多工厂时考虑 tenant 或 org_id)。

4.2 跟进记录(FollowUp / Interaction)

跟进记录要能精确复盘,最少字段:

  • id, customer_id, creator_id, create_time, follow_type(电话/邮件/上门/线上会议)、内容(富文本或markdown)、结果(意向/报价中/失效)、下次跟进时间(可空)、附件列表、关联订单/报价 id。

实现要点:

  • 每条记录带不可变的时间戳、创建者与编辑记录(审计)。
  • 支持 @提醒、状态流转、并且可关联到工单/合同/报价。

4.3 客户标签、分级与生命周期

  • 标签系统:自由标签 + 系统标签(VIP、重要、潜在风险、设计合作)。标签用于筛选和触发规则(例如:VIP 下单优先排产)。
  • 分级规则示例:可以采用 RFM(最近购买 Recency、频次 Frequency、金额 Monetary)结合交付准时率和投诉率,自动计算分级(A/B/C/D)。

4.4 客户分析(必须有的报表和告警)

关键指标:

  • 下单转化率(线索→报价→下单)
  • 平均报价响应时间、平均交期偏差、准交率
  • 客户等级分布、流失率(N 个月无下单)
  • 单均金额、下单周期分布、产品线购买占比

实现建议:

  • 把事实数据导入到 OLAP 层(如 ClickHouse 或专门的报表数据库),对关键指标做定时计算。
  • 对流失客户做常驻预警(如 90 天无下单且历史贡献 > X 的客户)。

5. 开发技巧与实现注意点(干货)

5.1 数据库与表结构(简要)

  • 使用关系型数据库(Postgres/MySQL)存客户主档和跟进记录。分析层可用 OLAP。
  • 跟进记录建议做 append-only 表,做软删除(is_deleted 字段),以便审计。
  • 指数设计:常用查询字段(customer_id、creator_id、create_time、状态、标签)需建联合索引。对于“最近下单时间”可以在客户表冗余存一列并在订单创建时更新,避免频繁 JOIN。

5.2 接口设计

  • REST 风格:分页(cursor 或 page+size)、筛选(标签/负责人/区域/最近下单时间区间)、权限过滤(数据隔离)。
  • 支持批量导入(Excel/CSV)与去重策略(根据税号/公司名模糊匹配)。
  • 支持模糊搜索(客户名/联系人/电话)——推荐用 Elasticsearch 或数据库的全文索引。

5.3 权限与审计

  • 角色权限:销售、销售经理、客服、财务、系统管理员。数据可见范围基于组织/团队/个人。
  • 审计日志:跟进记录任何编辑都记录差异(who/when/what),客户敏感字段(信用额度)修改需高级权限并记录审批流程。

5.4 并发与实时性

  • 跟进记录写入并发不高,但同时可能存在导入、API 写入、手动修改。注意事务边界,避免重复写入(使用唯一键或幂等 token)。
  • 实时性方面,关键的是“变更通知”:跟进后触发消息队列(RabbitMQ/Redis Stream/Kafka)推送给负责人/提醒系统。

5.5 性能与扩展

  • 列出常见性能瓶颈:模糊搜索、复杂分析查询、关联大量附件。解决方案:异步处理、缓存(Redis)、专用搜索服务(ES)、把历史跟进归档到冷表或归档库。

5.6 可靠性与数据质量

  • 导入/同步接口应有数据校验层(必填字段、格式、重复检查),并返回错误明细。
  • 设置“客户清洗”任务:定期合并重复客户、补全重要字段(如税号/结算方式)。

6. 参考代码(较大示例:TypeScript + Express + TypeORM 后端示例)

下面给出一个便于落地的后端示例,包含实体定义、主要 API、以及一个示例分析 SQL(用于计算 RFM)。代码经过注释,作为开发参考。

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany, Index } from 'typeorm';

import { FollowUp } from './FollowUp';

@Entity({ name: 'customers' })

export class Customer {

 @PrimaryGeneratedColumn('uuid')

 id: string;

 @Index()

 @Column({ type: 'varchar', length: 200 })

 name: string;

 @Column({ type: 'varchar', length: 100, nullable: true })

 short_name: string;

 @Column({ type: 'varchar', length: 50, nullable: true })

 type: string; // 'direct' | 'distributor' etc.

 @Column({ type: 'varchar', length: 100, nullable: true })

 industry: string;

 @Column({ type: 'varchar', length: 100, nullable: true })

 region: string;

 @Column({ type: 'jsonb', nullable: true })

 contacts: { name: string; phone?: string; email?: string; title?: string }[];

 @Column({ type: 'decimal', precision: 18, scale: 2, default: 0 })

 total_amount: number; // 累计下单金额冗余

 @Column({ type: 'timestamp', nullable: true })

 last_ordered_at: Date;

 @Column({ type: 'varchar', length: 50, nullable: true })

 tags: string; // simple csv tags, or use relation table

 @Column({ type: 'boolean', default: true })

 is_active: boolean;

 @CreateDateColumn()

 created_at: Date;

 @UpdateDateColumn()

 updated_at: Date;

 @OneToMany(() => FollowUp, fu => fu.customer)

 followUps: FollowUp[];

}

// src/entities/FollowUp.ts

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, Index } from 'typeorm';

import { Customer } from './Customer';

@Entity({ name: 'follow_ups' })

export class FollowUp {

 @PrimaryGeneratedColumn('uuid')

 id: string;

 @Index()

 @Column()

 customerId: string;

 @ManyToOne(() => Customer, c => c.followUps)

 customer: Customer;

 @Column()

 creatorId: string; // user id

 @Column({ type: 'varchar', length: 50 })

// src/entities/FollowUp.ts

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, Index } from 'typeorm';

import { Customer } from './Customer';

@Entity({ name: 'follow_ups' })

export class FollowUp {

 @PrimaryGeneratedColumn('uuid')

 id: string;

 @Index()

 @Column()

 customerId: string;

 @ManyToOne(() => Customer, c => c.followUps)

 customer: Customer;

 @Column()

 creatorId: string; // user id

 @Column({ type: 'varchar', length: 50 })

 type: string; // phone/email/visitation/meeting

 @Column({ type: 'text' })

 content: string;

 @Column({ type: 'varchar', length: 50, nullable: true })

 result: string; // 意向、报价中、失效等

 @Column({ type: 'timestamp', nullable: true })

 next_follow_at: Date;

 @Column({ type: 'jsonb', nullable: true })

 attachments: { name: string; url: string }[];

 @CreateDateColumn()

 created_at: Date;

}


7. 实现效果与交付验收建议

交付时建议验收列表(最少项):

  • 功能性:客户档案能创建/编辑/删除(软删除),联系人能管理,跟进记录可增删改查,并关联订单/报价。
  • 权限:不同角色看到正确的数据范围(销售只能看到自己负责的客户,经理能全公司查看)。
  • 性能:客户列表 95% 请求在 200ms 内返回(根据硬件与缓存)。
  • 数据质量:导入接口可展示错误明细并支持回滚。
  • 报表:至少有一张 RFM 报表和一个流失预警(邮件/钉钉/站内消息)。
  • 审计:所有跟进记录的编辑历史可查看。
  • 集成:能与报价服务和订单服务联动(至少通过 API 调用/事件总线)。

上线建议:

  • 先以“核心最小可用版本”上线(客户档案 + 跟进 + 简单分析),再通过迭代增加自动分级、预警、与生产的深度联动。
  • 做用户培训与流程文件(怎样填客户资料、跟进规范、标签规范),保证数据标准化。


8. FAQ

FAQ 1:客户管理模块一定要和外部 CRM 完全合并到 ERP 吗?

不一定。很多企业会同时使用专业 CRM(例如 Salesforce)和 ERP。在 MTO 场景下,关键是“数据一致性”和“流程联动”。建议做法是评估两个系统中的“主数据”归属:如果销售线索、市场活动、外部营销自动化以 CRM 为主,把 CRM 当作前端线索系统;而把 ERP 作为订单、报价、生产与账务的主系统。通过同步(双向或单向)接口,每次将客户主档和重要字段(信用等级、结算方式、最近下单时间)同步到 ERP,并确保在 ERP 中有来源标记与冲突解决策略。若预算允许,也可以把 CRM 的可视化和营销能力通过插件或嵌入方式接入 ERP 界面,减少用户切换。总之,是否合并要基于企业的组织方式、数据规模与成本评估,而不是简单地“全部搬到 ERP”。

FAQ 2:如何避免客户重复、数据不一致的问题?

客户重复通常来自多个入口(手工录入、导入、业务员个人 excel、外部 CRM 同步)。技术上要做三项工作:1)在写入层进行幂等和去重:用税号、统一社会信用码、公司名称 + 联系人电话等做多字段匹配,优先使用精确字段(税号)做唯一性约束;2)建立清洗与合并流程:提供后台合并工具,人工审核并合并重复档案(保留历史跟进与订单);3)在 UI 层提供实时提示:输入公司名时做模糊检索提示可能重复的客户,提示业务员先核查再新增。组织上要制定规范:谁有权限创建客户、创建时必须填写哪几个关键字段(税号/联系人/负责人),并做定期数据质量检查和指标(重复率、空值率)考核。

FAQ 3:如何结合客户跟进记录做自动化提醒与提高成单率?

跟进记录是业务的核心“记忆体”。要把它用好,可以做三件事:1)把跟进记录结构化,关键字段(跟进类型、结果、下次跟进时间、意向强度)标准化,便于机器识别;2)基于结构化字段建立规则引擎,比如“跟进结果=报价中 && 下次跟进时间 <= 今天 且 意向强度 >= 高”触发提醒给对应的销售并在系统中标红;3)把这些规则与分析结合,形成闭环优化:统计哪些跟进组合(如 1 次电话 + 1 次上门)转化率高,把最优跟进路径作为团队最佳实践。技术上提醒可以通过消息队列+通知服务(邮件、站内、企业微信/钉钉)实现;效果评估需要埋点和 A/B 测试(例如对一组客户采用系统化提醒,另一组不采用,观察成单率差异)。

相关文章
|
9天前
|
人工智能 运维 安全
|
7天前
|
人工智能 异构计算
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
|
8天前
|
机器学习/深度学习 人工智能 自然语言处理
B站开源IndexTTS2,用极致表现力颠覆听觉体验
在语音合成技术不断演进的背景下,早期版本的IndexTTS虽然在多场景应用中展现出良好的表现,但在情感表达的细腻度与时长控制的精准性方面仍存在提升空间。为了解决这些问题,并进一步推动零样本语音合成在实际场景中的落地能力,B站语音团队对模型架构与训练策略进行了深度优化,推出了全新一代语音合成模型——IndexTTS2 。
675 23
|
8天前
|
人工智能 测试技术 API
智能体(AI Agent)搭建全攻略:从概念到实践的终极指南
在人工智能浪潮中,智能体(AI Agent)正成为变革性技术。它们具备自主决策、环境感知、任务执行等能力,广泛应用于日常任务与商业流程。本文详解智能体概念、架构及七步搭建指南,助你打造专属智能体,迎接智能自动化新时代。
|
14天前
|
人工智能 JavaScript 测试技术
Qwen3-Coder入门教程|10分钟搞定安装配置
Qwen3-Coder 挑战赛简介:无论你是编程小白还是办公达人,都能通过本教程快速上手 Qwen-Code CLI,利用 AI 轻松实现代码编写、文档处理等任务。内容涵盖 API 配置、CLI 安装及多种实用案例,助你提升效率,体验智能编码的乐趣。
1105 110
|
人工智能 数据可视化 数据挖掘
Quick BI 体验&征文有奖!
瓴羊生态推出Quick BI 征文激励计划,鼓励用户分享数据分析实践经验与技术洞察,征集高质量原创文章。内容围绕AI功能体验与BI案例实践,设季奖、年奖及参与奖,优秀作者可获现金奖励、产品内测资格及官方认证形象。投稿截止至2026年3月31日。
Quick BI 体验&征文有奖!