恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

自研轻量级CRM:从数据库设计到权限与消息通知的实战清单

  • 首页
  • 资讯中心
  • /
  • 自研轻量级CRM:从数据库设计到权限与消息通知的实战清单

相关资讯

课设毕设赶不完?源码免费送----基于Java的琅琊文旅宣传网站的设计与实现 毕业设计源码21331 2026/9/19 13:58:45
PCIe驱动开发:ioremap与DMA映射原理及实战 2026/9/19 13:58:45
Aider 实战:TaoToken 跑通 5 个 SWE-bench 实例 2026/9/19 13:53:44

最新资讯

Cherry Studio 主进程架构解析:`src/main` 封闭顶层目录集合与依赖规则
VMware vCSA部署全流程:从OVF导入到VAMI配置详解
Hugo Site.BaseURL 方法详解:获取站点基础 URL 的正确姿势与替代方案
物联网导论教案PDF高效处理:从目录提取到可编辑文档实战
WRF模式Linux编译实战:NetCDF与MPI依赖配置指南
大模型认知机制:Prompt工程与思维链技术解析

今日推荐

oh-my-hermes:打造跨工具的命令编排与插件化工作流
OpenClaw.NET 用 /goal start 跑长任务,模型 Base URL 改到 TaoToken
SYB创业计划书财务逻辑拆解:从销售收入预测到现金流量计划

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

自研轻量级CRM:从数据库设计到权限与消息通知的实战清单

发布时间:2026/9/19 13:58:45
自研轻量级CRM:从数据库设计到权限与消息通知的实战清单 先讲个我自己的经历。两年前我们团队十来个人销售手里的客户信息大部分躺在Excel表、微信聊天记录和一张张便利贴里。一到月底统计业绩大家都在拼回忆老板最常问的一句话就是“这个客户上个月不是聊得挺好怎么突然没下文了”。后来实在扛不住我拉着开发同事自己动手做了一套轻量级的客户管理系统代码代号就叫DeskcommCRM。名字取Desk Communication的意思——桌面沟通核心就是把销售和客户的每一次交互都沉淀下来让客户跟进不再是“靠脑子记、凭感觉推”的玄学。这套系统解决的是小团队最常见的客户管理问题客户资料分散、跟进过程不透明、撞单扯皮、消息提醒缺失、数据统计靠人工。如果你正好也在纠结“要不要上CRM”“自己搭一套系统怎么下手”这篇文章可以当成一个完整参考。我会把从需求梳理、数据库设计、权限控制、消息通知到上线运维踩过的坑全部按实操顺序写清楚代码和SQL都是可以直接拿去改的。1. 先想清楚再做拆解DeskcommCRM的核心设计1.1 小团队用CRM真正的问题不是“没有工具”很多人以为CRM的核心是“记录客户信息”所以一开始就想做一堆字段、一大堆报表、各种复杂的审批流。结果做出来之后销售根本不用因为录入成本太高又看不到对自己卖货有啥帮助。我最初定方向时就跟团队说得很直接这套系统的使用对象是小团队里的销售和主管不是大公司里的运营专员。我们不需要汇总到集团层面的复杂报表不需要销售漏斗里几十个自定义阶段也不要审批流和报价单审批流程。我们只需要每天打开系统能回答这几个问题今天该跟哪个客户了昨天聊到哪一步了这个单子卡在哪儿我手里有多少条有效线索所以DeskcommCRM的第一条设计原则是以“跟进任务”为核心而不是以“客户档案”为核心。客户档案是静态的录入一次就完事价值有限跟进任务是动态的每天都会产生能改变客户状态、提醒下一步动作这才是销售真正每天要看的界面。这就像记账软件和提醒事项的区别。只做客户档案等于一个记账本大家新鲜两天就懒得记做了跟进任务和提醒等于给每个客户挂了闹钟系统每天主动告诉销售“该干活了”。后者的日活和使用率会完全不一样。1.2 模块划分宁可少不可杂DeskcommCRM的模块一开始只有四个客户管理、跟进记录、数据看板、用户权限。后面迭代加了消息通知和公海池但始终控制在可以一屏讲清楚的范围。每个模块我当初都问过自己一个问题这个功能是给谁用的他什么时候用不用行不行。客户管理是给销售创建和查询客户的不用不行跟进记录是给销售写每日进展、给主管看过程数据的不用不行数据看板是给主管和老板看转化率和订单来源的不用不行用户权限是保证数据隔离和撞单仲裁的不用会出事。那些“锦上添花”的功能比如产品库、合同管理、发票管理、报销审批我全部扔到了二期。原因是小团队还在验证销售流程跑不跑得通的时候塞进来只会增加成本和抵触情绪。很多团队自己做的CRM死掉不是功能太少而是功能太多、录入要求太苛刻最后销售觉得是在给公司写日记于是纷纷弃用。1.3 把“跟进记录”当成系统的心脏DeskcommCRM最核心的交互不是“新建客户”而是“写跟进”。我们规定销售每一次跟客户打完电话、聊完微信、见过面都要在系统里写一条跟进记录内容包括沟通要点、客户意向、下一步计划以及下次跟进时间。为什么这么看重跟进记录因为客户状态可能会骗人但跟进记录不会。销售把客户标成“意向强烈”主管一看跟进记录发现最近一条还停留在二十天前那这个“意向强烈”就是虚的。反过来系统里如果有一条条清晰的时间线哪一个节点客户提了什么需求、销售承诺了什么、谁跟进过后面接手的人五分钟就能掌握全部背景不用再翻聊天记录。数据层面跟进记录也直接驱动了“今日待跟进”列表和提醒通知。每天早上系统会根据每一条客户记录里的“下次跟进时间”字段拉出今天需要跟进的客户清单再通过站内信推送给对应销售。这一个功能看着简单但它是销售愿意每天打开系统的直接原因。利他才是强粘性。2. 核心功能细节从客户档案到销售漏斗的实操要点2.1 客户档案别把CRM做成通讯录客户档案的字段设计决定了销售的录入意愿。一开始我们做的客户表单很吓人有公司地址、官网、行业、规模、年营收、决策人职务、生日、兴趣爱好等二十多个字段。销售填了几条就骂人了说这哪是录客户是写户口本。后来我把表单砍成三部分基本信息必填只有客户名称、联系人、手机号、微信号、来源渠道选填有行业、公司地址、备注剩下全是系统自动记录的比如归属销售、创建时间、最后跟进时间、客户状态。这样销售建一个新的客户档案三十秒就能搞定想多写也有地方写但不再强制。联系电话建议做成唯一约束或者至少做索引因为我们后面发现很多撞单冲突都是由手机号重复引起的。这里有个实操教训同一个客户换了个联系人再加进来手机号不一样系统就识别不出来所以我在联系人表里做了“手机号 微信号”的组合去重逻辑录入时如果有疑似重复客户系统会提示让销售确认是继续新建还是关联到旧客户。2.2 跟进流程用状态机代替“感觉”客户状态在DeskcommCRM里是一个白名单状态机新客户、已联系、有意向、报价中、赢单、输单外加一个“暂停跟进”的异常状态。销售只能按顺序或者向后跳转不能随意把客户从“报价中”拉回“新客户”所有的状态变更都必须写一条跟进记录来触发。状态机的好处是数据口径统一。主观看法和真实数据不会打架主管看销售漏斗时知道每个阶段的客户是实打实走到那一步的不是销售拍脑袋填的。状态变更还可以用来触发提醒比如客户在“报价中”超过七天没有动静系统会给销售和主管各发一条提醒提示这个单子可能卡住了需要及时介入或者复盘。实际操作中状态机也会带来一个问题销售漏更新状态。比如客户已经进入报价阶段但销售忘了改状态后面看漏斗数据就会偏低。我的处理办法是当销售提交跟进记录时如果跟进内容里包含“报价”“合同”“价格”等关键词系统会自动弹出提示让销售确认是否需要变更客户状态。这种“自然语言的辅助校验”比强制下拉框要温和得多不会引起反感。2.3 数据权限老板、主管、销售的边界在哪里权限设计是CRM里面最容易顾此失彼的一块。DeskcommCRM里我用了最简单的角色模型三种角色管理员、主管、销售。销售只能看自己和公海里的客户主管可以看自己部门所有客户的详情和跟进记录管理员能看全部数据并且可以手动调整客户归属。这个模型没有细到“这个销售只能看华东区的客户那个销售只能看华南区”因为小团队一般用不到这么细的维度做了反而增加复杂度。但有一点必须做扎实就是数据权限的SQL过滤要写在后端不能只靠前端按钮隐藏。前端隐藏只是面子工程懂点技术的人绕过接口就能看到别人的数据。我当时给查询接口统一加了一个数据范围的注解后端在SQL层面自动追加“owner_id 当前用户”或者“department_id 当前部门”的条件。这样不管前端怎么改请求参数后端都会强制校验查不到越权的数据。3. 完整搭建过程数据库设计、权限与通知的实现3.1 需求优先级哪些功能先做哪些先砍掉正式写代码之前我先列了一张需求清单给每个需求标了优先级。P0是必须上的客户管理、跟进记录、客户状态、待办提醒、基础权限、数据看板。P1是最好有的消息通知、公海池、重复客户提醒、导入导出。P2是以后再说审批流、合同管理、产品库、对接企业微信。这套排序背后的逻辑是P0保证系统能形成“录入—跟进—更新—提醒”的闭环P1提高的是信息流转效率P2属于业务扩展。很多自己搭CRM的团队容易犯的错是一上来就想把P2做掉比如先做了一堆审批流程结果核心的跟进记录还没跑顺白白浪费时间。MVP版本上线第一周我们的目标是让每个销售每天花在系统上的时间不超过十分钟但要能覆盖一天的所有客户交互信息。这个目标定了之后很多功能自然就往轻量方向走了。3.2 数据库表设计五张核心表怎么定义DeskcommCRM数据库我用的MySQL 8.0字符集统一utf8mb4。核心表一共五张用户表、客户表、跟进记录表、提醒表、操作日志表。把业务概念控制在五个实体以内对于小团队的维护成本是最舒服的。客户表的结构大致是这样CREATE TABLE client ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL COMMENT 客户/公司名称, source TINYINT NOT NULL DEFAULT 0 COMMENT 来源0-未知 1-展会 2-官网 3-转介绍 4-其他, owner_id INT UNSIGNED NOT NULL COMMENT 归属销售ID, status TINYINT NOT NULL DEFAULT 0 COMMENT 状态0-新客户 1-已联系 2-有意向 3-报价中 4-赢单 5-输单, next_follow_at DATETIME DEFAULT NULL COMMENT 下次跟进时间, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_owner_status (owner_id, status), KEY idx_next_follow (next_follow_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT客户主表;跟进记录表是写入量最大的表我把它单独拆出来没有塞到客户表里。原因是跟进记录要支持按时间线分页查询和客户基本信息混在一起会造成冗余和慢查询。表结构长这样CREATE TABLE follow_record ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, client_id INT UNSIGNED NOT NULL COMMENT 客户ID, user_id INT UNSIGNED NOT NULL COMMENT 跟进人ID, record_type TINYINT NOT NULL COMMENT 1-电话 2-微信 3-见面 4-其他, content TEXT NOT NULL COMMENT 跟进内容, next_follow_at DATETIME DEFAULT NULL COMMENT 建议下次跟进时间, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_client_created (client_id, created_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT跟进记录表;提醒表我做成了一种“待办任务”模式每天定时任务扫描所有客户表的next_follow_at字段生成当天的待办提醒写入提醒表再通过站内信通知对应销售。这么做的好处是查询压力在凌晨定时批量完成白天用户查的是已经生成好的待办列表响应特别快。3.3 业务接口实现新增跟进记录这一步怎么做新增跟进记录是整个系统最核心的接口代码量不大但需要把几件事一次做完写跟进内容、更新客户状态、更新客户最后跟进时间信息、生成下次跟进提醒。如果用Spring Boot实现大致长这样PostMapping(/api/follow) public Result createFollow(RequestBody FollowCreateRequest req, RequestAttribute Integer userId) { // 1. 校验客户归属权非本人且非管理员不能操作 Client client clientMapper.selectById(req.getClientId()); if (client null) { return Result.error(客户不存在); } if (!client.getOwnerId().equals(userId) !isAdmin(userId)) { return Result.error(无操作权限); } // 2. 插入跟进记录 FollowRecord record new FollowRecord(); record.setClientId(req.getClientId()); record.setUserId(userId); record.setRecordType(req.getRecordType()); record.setContent(req.getContent()); record.setNextFollowAt(req.getNextFollowAt()); followRecordMapper.insert(record); // 3. 更新客户状态和下次跟进时间 clientMapper.updateFollowStatus(req.getClientId(), req.getStatus(), req.getNextFollowAt()); // 4. 生成待办提醒如果下次跟进时间不为空 if (req.getNextFollowAt() ! null) { reminderService.createReminder(req.getClientId(), userId, req.getNextFollowAt()); } return Result.ok(); }这里有两个细节值得展开。第一为什么要在新增跟进记录的接口里同时更新客户状态因为我认为每一个状态变更都应当对应一条跟进记录否则状态就是无源之水。第二生成待办提醒之后如果销售在记录的修改中发现下次跟进时间填错还需要提供修改接口同时把旧的提醒删掉再重新生成避免出现两条互相矛盾的待办。3.4 权限、提醒和消息通知的落地细节权限这一块前面提到了后端用数据范围注解自动拼接SQL。落地时我写了一个简单的DataScope注解加一个切面切面里根据当前登录用户的角色动态修改Mapper查询参数统一加WHERE条件。代码不复杂但非常管用有了这层兜底前端哪怕误操作或者被人抓包后端也返回不了越权数据。提醒和消息通知我用了两种方式一种是站内信用户登录系统后在右上角红点就能看到另一种是WebSocket实时推送当有人给自己分配客户或者领导调整了自己的客户归属时页面刷新会即时提醒。我用的Spring WebSocket STOMP协议前端用stompjs做订阅业务代码只需要在服务端发消息前端绑定好订阅路径即可。通知内容上我踩过一个坑一开始把所有提醒都做成站内信结果销售从来不开系统提醒就失效了。后来我加了定时任务的兜底每天上午十点把提醒表里当天未完成的待办项生成一份汇总推送到企业微信群里。这个改动比单纯做站内信有效得多因为大家看到群消息就条件反射去处理。// 前端WebSocket订阅示例 import { Client } from stomp/stompjs; const client new Client({ brokerURL: ws://你的域名/ws, connectHeaders: { token: localStorage.getItem(token) }, onConnect: () { client.subscribe(/user/queue/reminders, (message) { const reminder JSON.parse(message.body); showToast(您有新的待办客户 ${reminder.clientName}); refreshReminderList(); }); } }); client.activate();4. 上线半年后我踩过的坑和排查方法4.1 撞单判定怎么避免两个销售抢同一个客户撞单是小团队CRM里最敏感的事处理不好销售之间会闹矛盾。我的做法是建立“手机号 微信号”的组合唯一索引录入新客户时后端先查一次如果存在疑似重复就返回提示让销售选择“继续新建”或者“申请认领”。前者用于真是不同客户的情况后者会往主管那边生成一条仲裁待办。但只做录入时校验防不住另一个场景销售A手上有老客户销售B不知道把同一个联系方式当新客户录进去了。这种后录入的情况就需要主管介入仲裁把客户归给更早录入的一方并且把重复的记录合并掉。我在操作日志表里记录了合并前后所有的跟进记录防止合并过程把历史信息弄丢。上线初期我经常在后台处理合并请求后来我发现这类冲突次数会随着时间递减因为大家逐渐养成了先搜索、后新建的习惯。所以撞单规则不用一开始就做得特别复杂够用就好重点是有人要能快速仲裁。4.2 重复点击造成的数据重复有个阶段的Bug很让人头疼销售点击“提交跟进记录”按钮因为网络延迟点了好几次结果数据库里出现了五条一模一样的跟进记录。这个是典型的幂等性问题。解决思路分两层。前端先做提交按钮的loading防抖点击后按钮置灰这是第一道防线。后端做幂等性判断这是我真正放心的防线。我的做法是客户端生成一个请求唯一ID每次提交记录时带上后端在写入之前先查一下这个ID是否已经处理过处理过就直接返回上一次结果保证同一逻辑操作只执行一次。前端生成UUID一段代码就搞定后端加一个唯一索引把请求ID存进去重复插入会直接抛异常拦截后在业务层捕获并返回成功。这个设计方案看着简单但少了它用户在实际业务里一定会撞上重复数据问题。4.3 WebSocket通知断线失联的问题WebSocket通知上线初期经常出现一个问题用户登录后在页面上放着不管过一段时间再操作发现收不到新提醒了要刷新页面才正常。这个现象基本是WebSocket连接因为超时被服务端断开了但前端的Client对象没有更新连接状态导致消息推送就断了。我的排查思路是三步走。第一步打开浏览器开发者工具查WebSocket的连接状态看是不是变成了CLOSED第二步看服务端日志找有没有类似的Session超时关闭记录第三步检查前端心跳机制在STOMP客户端里开启自动心跳heartbeatIncoming和heartbeatOutgoing并且监听WebSocket关闭事件自动重连。真正修好后我发现断连只是表象根因是服务端的Tomcat默认空闲超时时间比较短WebSocket长连接挂着并不代表有消息流动服务端会按空闲策略把连接回收掉。我把WebSocket的超时时间调长并在前端加了重连机制这个问题才算彻底解决。线上环境一定要多做长连接断开的演练别等业务忙的时候才发现整个通知通道已经断了几个小时。4.4 Excel/CSV导入乱码与格式问题系统上线的时候我们要把销售手里的几百个老客户数据一次性导入系统。结果导入完一看中文全部乱码手机号有的变成了科学计数法有的丢失了前缀。乱码问题是因为销售提供的Excel另存成CSV时用的是本地化编码也就是GBK而我们系统读取的时候默认按UTF-8解析。解决方案不复杂后端在解析CSV文件时先读取文件头里的编码标记如果检测到没有UTF-8标记就用指定的GBK编码重新解析一次。手机号变成科学计数法是Excel自身展示问题我一般建议销售先把手机号列设置成“文本格式”再保存导入前后端再对字段做一次格式化处理去掉单元格里看不见的空格和换行符。导入前的数据校验我做了两步第一是逐行检查必填字段是否为空、手机号是否满足位数要求直接把问题行号和数据原因写进导入结果提示第二是重复客户在导入阶段就标记出来不自动过滤让主管看一遍再决定是否合并。这两步看着多花了一点时间但上线那一刻的数据库干净度直接影响后面所有统计的准确性。DeskcommCRM这套系统上线跑了小半年最有感触的一点是CRM工具能不能落地七分靠流程设计三分靠代码实现。技术上的权限、提醒、幂等这些问题都有标准解法真正决定成败的是有没有把“跟进记录”作为核心有没有让销售每天打开系统看到“今天该联系谁”有没有在撞单争议出现的时候给主管一个可靠的数据依据来判断。踩过几次坑之后我的体会是小团队自己搭CRM初期一定要克制先做透“录入—跟进—提醒—复盘”这条主线等大家真的依赖系统了再慢慢加东西。后续想做扩展的话可以优先考虑移动端H5的快捷登记入口以及对接企业微信群机器人的主动通知这两块对销售日常使用频率的提升最明显。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号