从Excel到自建轻量私有CRM:客户管理实践全记录
2026/9/19 20:34:58 网站建设 项目流程

提到客户管理系统,很多人第一时间想到的是Salesforce、销售易这类重型平台,功能全、配置复杂、实施周期长。我今天要聊的DeskcommCRM,则是一个完全相反的东西——它是我从零搭起来、带着一个小销售团队用了一年多的轻量私有CRM,核心只有一句话:把销售桌面上的客户资料、通信记录和跟进待办收拢到一个地方。如果你正被“客户信息散落在Excel、手机、聊天记录和一堆便利贴里”这件事折磨,或者团队规模不大但又不想被SaaS月费绑架,那这篇文章里从设计表结构到踩坑排查的全过程,应该能给你不少参考。文章会比较实操向,涉及数据库字段、消息规则、软电话对接、权限模型这些具体环节,也会写清楚我为什么在每一步做那样的取舍。

1. DeskcommCRM到底是什么:为什么我坚持桌面端为主的客户管理

1.1 从名字拆解产品定位:Desk + Comm + CRM

先说名字。DeskcommCRM这个词,拆开就是Desk、Comm、CRM三段。Desk表示“桌面”,不只是说它跑在电脑上,而是强调“坐席工作台”这个使用场景——销售每天上班,打开电脑就能看到今天该联系谁、哪些客户到了跟进日期、谁的通话还没补结论。Comm是Communication的缩写,对应通信能力:电话录音、通话弹屏、邮件记录、即时沟通摘要,这些在传统CRM里往往是独立模块,但在DeskcommCRM里是贯穿所有业务的主线。CRM则是客户关系管理的底座,客户档案、商机阶段、成交数据都沉淀在上面。

这个定位一开始就不是“给老板看报表的管人系统”,而是“帮销售少记点事的工作台”。传统CRM最大的问题在于:系统默认销售愿意主动录入数据。但实际上绝大部分销售最讨厌打字填表,电话打完还要去系统里新建跟进记录,时间一长就敷衍了事。DeskcommCRM的思路是反过来,把通信行为变成自动记录,让销售只补一句结论就行。这样客户动态不是靠人敲出来的,而是从每一次真实沟通里长出来的。

另一种取舍是移动端优先。很多产品喜欢搞一个App,让销售随时掏出手机录客户。但在实际操作中,销售的核心动作——打电话、回邮件、写报价、填合同——基本都在电脑前完成。手机端更适合在拜访现场临时查资料,而不是成为主要录入端。所以DeskcommCRM桌面端是完整能力,移动端只做了查看待办、接收提醒、审批和简单备注。这个选择让开发量大幅下降,也让数据质量稳定了很多,因为主录入通道只有一个,用户不需要在不同屏之间来回倒腾。

1.2 从Excel到CRM:我遇到的三类痛点

当时想自建这套系统,不是因为公司买不起现成的CRM,而是团队此前用Excel管客户,暴露出来的问题已经明显影响业务了。

第一个痛点是数据断裂。客户资料分散在销售个人电脑的Excel里、企业通讯录里、邮件签名里、手机通讯录里。老板问“上海区域这个季度到底接触了多少客户”,没人能给准确数字。部分销售自己记录得详细,但格式五花八门:有人把客户等级写在备注栏,有人把下次跟进时间写在一个黄色单元格里,还有人在文件名里加日期表示“最新版”。这些习惯一旦换人接手,基本等于资料作废。

第二个痛点是交接断层。销售离职时,公司能拿到的只有一份Excel。可这份Excel里往往只有客户名称、联系人和电话,没有历史沟通记录、没有报价背景、没有关键决策人的偏好。新接手的人面对陌生客户,只能硬着头皮重新电话开场,很多客户就是这样被“丢”掉的。更麻烦的是,有些老销售会把客户信息存在私人聊天记录里,人一走信息也跟着走了。

第三个痛点是跟进无闭环。Excel里就算写了“下次跟进时间”,也没有人能保证那天真的会跟进。销售靠脑子和便利贴记待办,忙起来必然漏。没有系统层面的提醒和统计,主管也很难知道一个销售手头到底有多少客户到了该联系的日子。DeskcommCRM要解决的,就是这三件事:数据有固定结构、沟通有历史沉淀、跟进有系统提醒。

2. 核心业务模型设计:客户档案、跟进记录与商机流转

2.1 客户表字段设计:先定好唯一标识

任何CRM最先要定的都是数据模型,不是界面。DeskcommCRM第一版把模型控制在“客户、联系人、跟进记录、商机”四个核心实体,没有一开始就上复杂的订单和库存体系。客户表我做了这样的设计:

CREATE TABLE customers ( id BIGSERIAL PRIMARY KEY, customer_no VARCHAR(32) NOT NULL UNIQUE, company_name VARCHAR(200) NOT NULL DEFAULT '', contact_name VARCHAR(100) NOT NULL DEFAULT '', mobile VARCHAR(30), work_phone VARCHAR(30), email VARCHAR(200), region VARCHAR(50), source VARCHAR(50), owner_id BIGINT, status VARCHAR(30) NOT NULL DEFAULT 'leads', level SMALLINT NOT NULL DEFAULT 0, last_contact_at TIMESTAMPTZ, next_follow_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), version INTEGER NOT NULL DEFAULT 1, deleted_at TIMESTAMPTZ, remark TEXT );

这里面有几个设计是踩过坑之后才补上的。第一个是customer_no,这是客户在系统里的唯一业务编号,不用自增id的原因是后续要打印、导入导出、跨系统对接,用一个带规则的编号比“12345”这种纯数字更直观。第二个是mobile和work_phone分开,很多To B公司一个联系人既有手机又有固话,混在一个字段里会导致搜索和电话匹配困难。第三个是version字段,这是乐观锁,用来解决多人同时编辑一个客户时互相覆盖的问题,后面我会单独讲。

还有一个容易忽略的点是deleted_at软删除。一开始我认为物理删除最省事,后来才发现销售误删客户、主管想找回历史记录都是高频需求。改为软删除后,列表页默认过滤掉deleted_at非空的数据,但管理员后台还能看到被删记录,也能一键恢复。历史数据不能丢,这在CRM里是一条铁律,因为客户关系本身就是企业资产,删了就真的没了。

关于手机号是否要设为唯一索引,我建议是不要。因为同一个号码可能属于一个客户下的多个联系人,也可能客户注销后重新分配给新的企业联系人。如果强制唯一,导入历史数据时就会大量报错。正确的做法是建立普通索引,在“搜索客户”时用电话号码快速匹配,而不是把电话号码当作主键。

2.2 跟进任务机制:如何让销售不再漏跟踪

客户档案建完之后,另一个关键就是跟进记录。这段是DeskcommCRM使用频率最高的模块,因为每一次和客户的实质接触都会落在这里。跟进记录表我采用了偏事件流的结构:

CREATE TABLE follow_up_logs ( id BIGSERIAL PRIMARY KEY, customer_id BIGINT NOT NULL, owner_id BIGINT NOT NULL, contact_type VARCHAR(20) NOT NULL, contact_time TIMESTAMPTZ NOT NULL DEFAULT now(), summary TEXT NOT NULL DEFAULT '', status VARCHAR(20), call_duration INTEGER, recording_url TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now() );

contact_type我取了call、email、onsite、im、other这五类,分别对应电话、邮件、拜访、即时聊天、其他。这个枚举不要轻易扩展,类型越少,报表统计越干净。比如“微信语音”本质上也是call,“微信文字”可以归为im,销售不需要纠结分类,系统才能得到一致的统计口径。

跟进任务的核心不在表结构,而在规则。DeskcommCRM里有一个自动待办引擎,规则是这样的:每次电话结束或邮件发出后,系统自动为这条客户记录生成一条“待补充跟进结论”的待办;如果后续补了summary,待办自动消除。客户等级为A的48小时内必须再次联系,B级7天内,C级30天内,系统每到临界点就会在桌面端弹提醒。

实际上,待办提醒能不能起作用,要看提醒的打扰程度。刚开始我们设置成每5分钟弹一次,结果销售烦到直接静音整个应用。后来改成每天早上9点推送“今日应联系清单”,下午4点推送“今日未完成跟进提醒”,只推两次,反而大家都在用。销售不是不愿意跟进,而是需要有人在合适的节点帮他把待办摆到眼前。

2.3 商机阶段与“公海回收”规则

客户从线索到成交,中间会经过多个状态。DeskcommCRM预设了一条状态流:leads(新建线索)-> contacted(已联系)-> qualified(意向明确)-> proposal(方案/报价中)-> won(成交)-> lost(流失)。

很多人觉得这个状态流太死板,销售想怎么点就怎么点。我坚持要做状态机约束,因为如果销售可以随意从leads跳到won,那主管看到的转化率就是假的。实际实现时,DeskcommCRM在后台定义了每个状态的可达切换,比如从leads只能到contacted或lost,不能直接到won。只有主管角色可以强制纠偏,普通销售没有越级变更权限。

公海机制是这个模块里最实用的设计。所谓公海,就是一个所有销售都能看到但不能随意认领的客户池。规则是这样的:客户在某个销售名下超过30天没有产生任何跟进记录,系统自动释放到公海;公海里被销售认领后,7天内必须至少有1次有效跟进,否则自动退回公海。这个规则彻底解决了“占着客户不干活”的问题,也让沉睡客户能重新被激活。

有人会问,公海会不会导致销售互相争抢客户?实际上不会,因为认领公海客户时系统会记录认领时间,同一批客户短时间内只能被同一个人认领有限次数,而且是先到先得。从运营效果上看,公海机制让团队多产出了不少“捡回来的客户”,很多客户并非没有需求,只是原负责销售没有及时跟进,被释放后换个销售重新接触,反而有了新机会。

3. 实现路线与关键技术选型:本地优先的私有部署

3.1 为什么我没直接采购SaaS,而是自建

在很多情况下,买一个成熟的CRM是最快、最省心的方案。但当时我选择自建DeskcommCRM,有几个非常具体的理由。

第一是数据敏感度。客户电话、报价记录、合同金额这些数据,公司管理层明确希望留在自有服务器上,不想放在公有云SaaS平台。很多行业客户也会问“你们的数据存在哪”,如果销售自己都没法回答这个问题,会直接影响信任度。私有部署意味着数据资产完全可管控,备份、迁移、销毁都有明确路径。

第二是定制成本。市面上的CRM功能很多,但真要落地到“通话弹屏”“按团队规则自动释放公海”“桌面端提醒”这些场景,多数产品要么不支持,要么在高阶版本里。真等采购流程走完,业务需求可能都变了。自建虽然要投入开发人力,但胜在逻辑可控,想调整规则随时改代码。

第三是长期费用。按坐席收费的SaaS,几十人的团队一年下来也是笔不小的支出。私有部署的软件侧成本主要集中在初期开发,硬件一台服务器就够了。当然,自建也意味着要自己面对备份、升级、故障恢复这些运维问题,没有免费的午餐。

如果团队里完全没有专职技术人员,我其实不建议走自建这条路。DeskcommCRM这套方案更适用于公司内部已有一定研发能力、希望把客户数据掌握在自己手里的团队。自主研发不是目的,数据可控和流程适配才是。

3.2 技术栈、目录规划与核心依赖

DeskcommCRM的技术栈并不花哨:桌面端用Electron + Vue 3,后端用Python FastAPI,数据库用PostgreSQL,缓存和任务队列用Redis,部署用Docker Compose。这套组合在当时很成熟,社区排障资料多,团队也熟悉,没必要为了追求新框架去冒风险。

选Electron而不是纯Web,最主要的原因是桌面提醒和来电弹屏。浏览器网页在最小化时,定时器会被后台挂起,通知能力也受限;Electron则可以常驻系统托盘,来电时通过主进程拉起置顶窗口,这个体验比浏览器标签页稳定得多。代价是安装包体积大、内存占用高,但公司内网电脑配置普遍不差,可以接受。

项目目录结构大致是这样的:

deskcomm-crm/ ├── client/ # Electron + Vue3 桌面端 │ ├── src/ │ └── build/ ├── server/ # FastAPI 服务端 │ ├── app/ │ ├── models/ │ └── api/ ├── worker/ # 定时任务与提醒队列 ├── migrations/ # 数据库迁移SQL ├── scripts/ # 数据导入、号码清洗 ├── deploy/ │ ├── docker-compose.yml │ └── nginx.conf └── docs/

为什么要把server和worker分开?因为跟进提醒、公海释放、数据归档这类定时任务不能塞在API进程里跑。FastAPI主进程如果被一个长时间运行的报表查询拖住,会导致接口响应慢。worker独立进程消费Redis任务队列,既不影响API性能,也方便单独扩容。这个拆分大概只有几十行代码的额外成本,却让系统稳定性和可维护性高了一个档次。

PostgreSQL是这套系统里我最不担心出问题的部分。它的JSONB字段在保存灵活配置时很好用,比如客户等级、来源这类枚举值调整,不需要频繁改表。事务能力和并发控制也可靠,CRM里大量涉及“认领客户”“修改归属”这类操作,一旦并发出错就是客户归属纠纷,数据库层面必须顶住。

3.3 通信集成的实现思路:软电话弹屏与话单沉淀

DeskcommCRM跟传统CRM拉开差距的关键模块,就是通信集成。我们的方案是自建PBX(基于Asterisk),通过AMI接口与CRM对接。这套架构简要说的话:销售在系统里绑定自己的分机号,客户来电时,PBX产生一个呼叫事件,携带主叫号码;CRM服务端收到事件后,用号码去客户表里匹配,匹配成功就把这个客户的资料和全部历史记录推送到桌面端弹窗。

弹屏只是表面功能,更重要的价值是通话结束后自动生成一条话单。通话时长、通话时间、录音文件URL一并写入follow_up_logs,销售只需要在弹窗里补一句“客户对XX方案有兴趣,下周三再联系”。如果没有自动话单,销售很可能打完电话就忘了记录,手工补录的积极性会随着电话数量增加急剧下降。

关于怎么发起外呼,我建议用回拨模式,而不是在浏览器里做WebRTC软电话。回拨的操作是:销售在CRM里点击呼叫按钮,后端调用Asterisk的Originate动作,Asterisk先呼叫这个销售的分机,销售接起来后,Asterisk再呼叫客户号码。两边接通后,系统开始录音。这个模式的优点是音频质量稳定、不依赖电脑麦克风,也避开了浏览器音频设备授权、回声消除、断线重连这些乱七八糟的问题。

号码归一化是通信模块最容易踩的坑。同一个客户可能在Excel里存成“138 0013 8000”,在话机里显示为“+8613800138000”,在微信里记录成“13800138000”。如果不做归一化,来电弹屏就很难稳定匹配。我写了一个清洗函数,统一去掉空格、横杠、括号,区号统一补全,手机号统一转成E.164格式。这个函数虽然不起眼,但它是弹屏准确率的重要保障。

4. 上线后的典型问题与排查经验

4.1 多人编辑冲突:版本号与编辑锁

上线第一周,我就遇到了一个非常现实的并发问题:同一个客户,两个销售同时打开编辑,后保存的那个把先保存的覆盖了。尤其是在共享客户和公海交接阶段,一个客户可能有销售A和主管B都在操作,一个改备注,一个改等级,最后谁后点保存,另一个人的改动就丢了。

第一版我天真地以为“last write wins”就够了,直到用户投诉“我明明写了三行备注,保存后变成空的了”。后来在更新语句里加了版本号校验:每次update时,where条件带上version,成功后将version加一。如果update影响行数为0,说明版本已被别人改动,客户端就会收到“客户资料已被其他同事更新,请刷新后重试”的提示。

还有一种更高强度的方案是编辑锁,用户打开编辑页时占用一把锁,其他人只能以只读方式查看。但这对体验影响很大,因为销售经常编辑到一半去接电话,锁会卡住别人很久。DeskcommCRM最终采用“乐观锁 + 保存时冲突提示”的方案,不阻止编辑,但保证不会无声无息地覆盖数据。这也是很多成熟CRM采用的策略,轻量且有效。

4.2 来电不弹屏:号码归一化与CTI事件排查

通信模块上线后,排障频率最高的就是“来电为什么不弹屏”。运维日志看多了之后,我总结了排查顺序:先看PBX侧是否产生了呼叫事件,再看CRM是否收到AMI事件,再看号码匹配是否成功,最后看桌面端弹窗代码有没有被系统拦截。

有几次的问题是分机没有透传主叫号码,AMI事件里呼出号是空的,CRM自然无法匹配。这个要去Asterisk的呼叫配置里确认CallerID的设置。还有一次更隐蔽:客户手机号码在系统里存的是“13800138000”,但话机上显示的是“+8613800138000”,虽然看起来是同一个号码,程序按字符串匹配永远匹配不上。这就是为什么号码归一化必须放在事件接收的第一道工序,而不是等到匹配那一步再处理。

桌面端弹窗被拦截也是常见问题。Electron程序在Windows上如果没设置合适的系统通知权限,弹窗可能被静默拦截。特别是在部分企业安全软件环境下,置顶窗口会被要求额外授权。这个坑不是代码层面能完全解决的,需要在部署文档里明确写上“给DeskcommCRM设置允许置顶和通知权限”这类注意事项。

4.3 权限边界:共享客户与私客的划分

权限设计在前期不够严谨,后面补起来代价很高。DeskcommCRM第一版只有一个“管理员/普通销售”的区别,结果主管想查看下属客户,却没有权限入口;普通销售想编辑公共客户,又总是操作受限。后来改成三套数据权限维度:客户归属、客户状态、操作类型。

客户归属分成三种:私客(只归自己管)、共享客户(至少两个销售同时可见,比如同一个连锁集团的不同门店)、公海客户(所有人可见但需要认领)。客户状态分为线索和正式客户,线索状态下其他销售还能看到一些基础信息,变成正式客户后默认只对负责人和主管开放。操作类型则细分为查看、编辑、删除、转移、导出,每个角色单独配置。

这个模型用起来之后,最明显的改变是责任边界清楚了。共享客户不是所有销售都能随意改,只有绑定的share_permission里列出的角色才能编辑。主管拥有团队内所有客户的全部操作权限,但普通销售即使看到了公海客户,也不能删除任何记录。这套权限模型虽然初始配置麻烦,但避免了后续大量人为纠纷。

4.4 常见问题速查表

这里整理一份排障速查表,都是我实际遇到过的。每一个问题背后对应着一个容易忽略的原理,弄清楚原理之后,再遇到类似问题就有迹可循。

现象常见原因解决办法
来电不弹屏分机未透传主叫号码或号码格式不一致检查PBX的CallerID配置,事件接收后先做号码归一化
保存后数据被覆盖缺少乐观锁或版本号校验update条件带上version,冲突时提示刷新
待办不提醒Electron后台定时任务被系统挂起提醒改成服务端WebSocket推送,客户端只负责展示
录音文件无法播放文件名中文或音频格式不支持统一使用英文文件名,转成mp3/wav格式
报表数据对不上物理删除了历史客户,统计时没有过滤改用软删除,所有报表默认过滤deleted_at
公海客户迟迟不释放定时任务进程挂掉,没有重试机制worker进程加守护,任务失败自动重试

这张表特别适合上线初期贴在运维文档里。CRM系统本身逻辑不算复杂,但涉及到电话、桌面端、定时任务多个环节,链路一长就容易“这里漏一点、那里漏一点”。事后排查时如果一头扎进代码里翻,效率很低,按链路一层层剥离会快得多。

5. 从落地到提效:DeskcommCRM在团队里的实际变化

5.1 销售习惯被改变的真实细节

工具上线并不等于被使用,真正改变团队习惯花了一个多月。初期最大的阻力来自销售:“又要额外维护一个系统,这不是增加工作量吗?”我后来调整了策略,不强制要求销售填写一大堆客户画像,而是先把“自动生成通话记录”这个能力做扎实,让销售打完电话发现自己不用录太多东西,系统的价值就开始被认可。

一个很有意思的细节是,以前销售在微信或飞书里聊完客户,经常会说“这事我记一下,回头填到表里”,然后就没有然后了。DeskcommCRM上线后,我们把即时沟通的结论回填做成了“轻流程”:聊天窗口旁边直接有个“记录摘要”按钮,点一下弹出一个极简输入框,只需要写一句话。这个按钮把记录动作从“打开CRM找客户再录入”简化成“点一下直接记”,使用频率提升了至少一半。

销售主管也明显省力了。以前每周一例会上,主管要逐个问“你手上那几个客户进展怎么样”,销售往往含糊带过。现在打开DeskcommCRM的看板,每个客户的最后跟进时间、下一次跟进日期、当前商机阶段一目了然,会议从“汇报工作”变成“讨论卡点”。团队里再也没人问“上个客户聊到哪了”这种问题,因为历史记录就在那里。

5.2 数据报表带来的管理价值

有了准确、结构化的数据之后,报表才真正有价值。DeskcommCRM后台主要看四个指标:跟进完成率、首次响应时长、商机转化率、公海回收率。跟进完成率衡量的是“该联系的客户是否按时联系了”,首次响应时长衡量的是“新线索进来多久被跟进”,商机转化率衡量的是销售把客户推进到成交的能力,公海回收率则是看沉睡客户有没有被重新激活。

以前用Excel的时候,这三个指标根本算不出来,因为数据分散且格式不一。系统上线后,主管每天只需要扫一眼Dashboard,就能知道哪个区域、哪个销售的漏斗出了问题。有一次我们发现某个销售跟进完成率只有50%,跨进公海被释放的客户不少,私下了解才知道他手头客户太多,分配机制不合理。这个发现不是靠经验猜出来的,而是数据直接暴露了问题。

关于是否把个人数据排名公开展示,我的原则是只让每个销售看到自己的数据,主管能看到全团队数据。如果公开排名,短期内打鸡血效果好,但长期容易引发恶性竞争,尤其共享客户多的团队会很敏感。反而让每个人盯住自己的转化漏斗,内部比较自然产生,氛围更健康。

5.3 后续可以扩展的方向:语音转写、自动化规则、移动端

DeskcommCRM目前是一个够用的版本,但它还有几个我明确规划过但没在当前版本里实现的方向。第一个是语音转写,把通话录音转成文字摘要,再自动提取待办事项。技术上Speech-to-Text已经很成熟,难的是销售专业术语的识别准确率,需要收集团队历史通话录音做自训练。这个功能如果能落地,跟进记录可以从“销售手写一句话”变成“系统自动生成摘要,销售只需校对”。

第二个是自动化规则引擎。目前公海释放、待办提醒这些规则都是写死在代码里的,改动要发版。后续可以做成可视化配置,主管在后台设置“超过25天未跟进就释放到公海”“A类客户超过48小时未联系则通知主管”这类规则,不需要开发介入。这样系统可以逐步从“技术驱动”转成“业务驱动”,更灵活。

第三个是移动端。虽然我一直强调桌面端为主,但销售外出拜访时,查看客户历史和现场下单的需求确实存在。移动端不需要做复杂字段,只要做到“查看客户、写跟进摘要、看待办、审批”四件事就好。这个定位在后续如果有团队愿意继续迭代,建议优先考虑。

一点个人体会

如果让我重新做一遍DeskcommCRM,我不会先写界面,而是先把“客户、联系人、跟进记录、商机”这四个核心模型和各自权限边界定清楚。数据模型错了,后面改schema的代价远比想象中大。另一个深刻的体会是:CRM这类工具真正难的不是技术实现,而是让销售愿意把信息交出来。DeskcommCRM之所以能撑住这一年的运营,核心在于我们花了大量时间在减少销售录入成本上——电话自动生成记录、弹屏自动匹配客户、点两下完成跟进。工具不好用,规则定得再严也白搭。后来我在做其他系统时也一直保持这个原则:凡是需要用户主动填写的字段,先问一遍能不能自动生成;凡是需要多步操作的流程,先想一步能不能省掉。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询