从零自建私有化CRM系统:基于若依框架的二次开发与部署实践
发布时间:2026/9/16 6:49:02 作者:尧图编辑部 阅读量:1,286

做客户管理系统这事光有想法是不够的。我最近把一个叫DeskcommCRM的私有化 CRM 项目从零推到团队日常使用中间那些选型、开发、部署、上线、收尾的细节拿出来跟各位同行聊聊。这不是买一个现成 SaaS 账号那么简单而是一套通过云服务器把自己域名绑定上去、7x24 小时随时可访问的“永久在线”客户管理系统客户资料、线索、商机、跟进记录、合同回款全部管起来。如果你也在纠结“要不要自建一套 CRM”或者已经决定要干但不知道从哪下手这篇文章应该能帮你少走不少弯路。我会把我实际操作中遇到的坑、为什么做某个选择的理由、以及那些常规文档里不会写的细节全部摊开来讲清楚。1. 先搞清楚 CRM 到底在解决什么问题很多人聊 CRM第一反应就是“给销售用的客户通讯录”。这个理解不算错但很容易把项目做偏。我接手 DeskcommCRM 之前先花了两天时间梳理实际业务痛点因为我发现只有先把“要解决什么”想明白后面的表结构、字段、权限设计才能落地否则做出来就是一个没人用的花架子。1.1 数据分散是大多数团队的第一道坎小团队的客户数据通常散落在几个地方销售手机通讯录、个人微信聊天记录、Excel 表格、草稿本上的名片甚至全凭大脑记忆。这种模式一个人单打独斗没问题但只要有了第二个人麻烦立刻出现。我当时和团队里的几个销售聊过听到最多的问题是这样的某客户不知道是不是已经被同事跟进过结果打了电话过去客户说“你们昨天刚有人联系过我”。主管想统计一下这周新增了几个客户销售只能凭记忆报数数字对不对全看良心。销售离职他手里那批客户资源就跟着微信好友一起带走公司毫无办法。这些问题的根源只有一个客户数据没有统一沉淀。CRM 的第一价值就是把分散在个人手里的客户信息集中到一个数据库里让客户从“个人的”变成“公司的”。1.2 CRM 不是客户登记表而是业务推进引擎只做到“登记客户”是不够的那是客户管理软件不是完整的 CRM。DeskcommCRM 的核心定位是“业务推进引擎”也就是说每一条客户数据都要在系统里流动起来线索进来分配给销售销售跟进转成商机推进到报价最后成交回款。这个流动过程有几个关键动作需要系统支撑线索进入后有明确归属人未分配的线索进线索池销售可以自行认领或由主管指派每次沟通都留下跟进记录下次跟进时间自动提醒避免把客户跟丢商机按照阶段推进每个阶段的停留时间、金额变化都有日志管理层打开报表就能看到销售漏斗到底堵在哪一环。从“记录”升级到“推进”这是 CRM 能不能真正落地使用的分水岭。1.3 谁适合用 DeskcommCRM 这类自研方案不吹不黑不是所有团队都适合自建 CRM。我总结了下适合用这类方案的是三种情况业务团队有 10 人以上客户量上千靠 Excel 已经明显管不过来对数据敏感不希望客户资料存放在第三方平台尤其是涉及报价、合同这类商业信息长期有定制需求比如后续要接企业微信、做自定义报表SaaS 版本功能边界满足不了。反过来如果团队只有三五个人客户总共几十个买一套轻量 SaaS 足够或者业务流程极不标准连销售漏斗都谈不上那 CRM 上了也是浪费精力。工具要匹配阶段别为了上系统而上系统。2. 技术方案选型为什么走“成熟框架二次开发”路线做 CRM 之前最大的技术决策就是选型。我在这一步花了比较多时间因为这里选错了后面全盘都要返工。DeskcommCRM 最终选择了基于若依RuoYi前后端分离版做二次开发这个决定是经过反复比较之后定下来的。2.1 三条路线纯自研、开源改造、SaaS 订阅把市面方案粗分一下主要有三条路走路线代表优点缺点纯自研自己从零写完全可控想怎么做都行开发周期长权限、组织这些基础功能容易翻车开源改造RuoYi、RuoYi-Vue、RuoYi-Office 生态基础能力现成定制空间大免费需要有能力读懂并改代码SaaS 订阅纷享销客、飞鱼 CRM、销售易上线最快开箱即用数据在别人手里定制少按年付费越来越贵至于“到底哪个好”关键看团队条件。我当时明确排除了纯自研权限体系、部门管理、字典管理、日志审计这些基础模块自己写至少要多花一个月而若依已经在生产环境摸爬滚打很多年相对更稳。SaaS 也被否掉了不是因为产品不好而是我们后续有大量自定义场景比如要对接企业微信自定义应用、要按行业定制商机阶段SaaS 上改起来特别痛苦还有不断上涨的按年费用。所以最后走了中间路线若依框架打底自己加 CRM 业务模块。RuoYi 提供用户、角色、菜单、数据权限、定时任务、Redis 缓存这些通用能力我们把精力集中在客户管理、线索商机、跟进回款这些业务功能上。这也是很多“RuoYi Office CRM”类项目能快速落地的原因。2.2 免费 SaaS CRM 和自部署“私人网站”的本质区别网上经常有人搜“免费 CRM 和私人网站的区别”其实说的是两类完全不同的东西。免费 SaaS CRM 是厂商在云端开好账号给你用而所谓的“私人网站”本质是自己买一台云服务器把 CRM 系统部署上去通过公网访问数据和代码全在自己手里。我做了个对比这两类的差异非常明显数据主权免费 SaaS 版本免费代价往往是数据导出受限、平台方能看到你的客户信息自部署 CRM 的数据库就在自己服务器上随时能导出 SQL数据完全由自己掌控。成本结构SaaS 按年付订阅费免费版功能有打折自部署是一次性开发或部署投入加上每月百八十块的服务器费用长期算下来更可控。定制边界SaaS 你能改的只有设置项字段不够、流程不对只能找客服提需求自部署可以改代码想加“回访计划”就加表、加页面自由度完全不同。稳定性责任SaaS 挂了是服务商的责任你只能等自部署挂了是自己维护需要有人懂 Linux、Nginx、数据库稳定在线的前提是运维跟得上。所以“免费”不等于“不要成本”自部署也不等于“高不可攀”。两者满足的需求不同选择之前先想清楚自己更看重哪一头。2.3 技术栈清单与开发环境准备DeskcommCRM 最终技术栈是这样的后端JDK 8、Spring Boot 2.7.x、MyBatis-Plus、MySQL 8.0、Redis 6.x前端Vue 3、Element Plus、Vite前端工程独立打包中间件Nginx 做反向代理XShell 或 FinalShell 做服务器管理部署方式jar 包部署 systemd 守护进程本地开发环境的准备步骤我列一下安装 JDK 8配置好JAVA_HOME和PATH安装 MySQL 8.0创建一个独立库create database deskcomm default character set utf8mb4;安装 Redis默认端口启动设置访问密码这里不要偷懒安装 Maven 3.6配置国内镜像源加速依赖下载安装 Node.js 16前端依赖用 npm 安装。用这些工具时有两点要提醒MySQL 的字符集一定要用utf8mb4不然客户备注里存个生僻字或表情可能报错Redis 的密码不要写在代码里用配置项从application.yml外面注入比较安全。2.4 项目整体骨架怎么搭基于若依二次开发时我没有把代码全堆在一个模块里而是做了模块划分方便后续维护deskcomm-admin启动入口deskcomm-system部门、用户、角色、菜单、日志等系统基础功能deskcomm-crm客户管理、线索管理、商机管理、跟进记录、合同回款这些业务模块deskcomm-quartz定时任务比如扫描“明天到期未跟进的客户”自动生成提醒任务模块划分清楚之后写业务代码时就不用在几万行代码里找文件了。前端目录也按业务拆成views/crm/customer、views/crm/clue、views/crm/business、views/crm/contract等几个大文件夹新增一个模块就是新建一个目录的事结构清爽很多。3. 核心功能模块的拆解与实现框架搭好之后真正花时间的是 CRM 业务模块的设计。这里不写完整代码我把我设计的几个核心模块的思路和关键字段讲清楚复制到自己的业务里基本能直接改着用。3.1 客户与联系人一个客户到底要建几张表客户是 CRM 的基石。我设计客户相关表时没有只建一张客户表而是拆成了四张客户表、联系人表、客户标签表、客户操作日志表。客户表核心字段包括customer_name客户公司或个体名称contact_person主要联系人姓名phone / email联系方式level客户等级A/B/C/Dsource客户来源展会、转介绍、官网、电话industry行业owner_id归属人销售status状态潜在、合作中、流失这个表设计时要特别注意归属人字段。owner_id建好普通索引因为按销售统计客户量、查“我名下的客户”都要靠这个字段筛选没索引数据一大就卡。客户和联系人为什么要分两张表一是因为一个公司可能对接多个联系人二是联系人的手机号、微信和客户主体属性关系不大放一起会显得表非常宽后期查询慢。3.2 线索与商机销售漏斗是怎么转起来的线索和商机容易混我用一句话给团队解释线索是“还没有确认意向”的潜在客户商机是“已经确认有购买意向”并且进入了销售流程的客户。线索表在设计时多加了几个字段source渠道来源、demand需求描述、status新线索、已认领、跟进中、已转化、作废。销售可以在线索池里看到所有未认领的线索点“认领”之后这条线索就是他的了。当你判断一条线索真的有意向就把它“转化为商机”。“转化”动作在系统里不只是一个按钮它会做三件事把线索状态改成“已转化”在商机表新增一条记录并把客户信息带过去在跟进记录里留一条“线索转化为商机”的日志。商机表关键字段是business_name项目名称、customer_id、amount预计金额、deal_date预计成交时间、stage阶段。商机阶段我按实际业务放的是初步接触、需求确认、方案报价、商务谈判、成交赢单、流失作废。每次阶段变更都会记录变更时间和操作人最终看漏斗报表时能清晰看到每个商机在哪个阶段停留了多少天如果超过设定天数还没有动作就该有人介入去催了。3.3 跟进记录与任务提醒别把客户跟丢了跟进记录是销售团队最常用的功能也是决定 CRM 能不能坚持用下去的关键。设计的核心不是“能记”而是“记得方便、记得提醒”。跟进记录表字段customer_id关联客户follow_type跟进方式电话、微信、拜访、邮件content跟进内容next_follow_time下次跟进时间owner_id跟进人为什么一定要有next_follow_time因为 CRM 不只是给销售自己看的更是用来避免“跟进遗漏”的工具。我在系统里做了一个定时任务每天早八点扫描所有next_follow_time在未来三天内且未完成的跟进记录自动给负责人生成一条待办任务并推送提醒到站内消息中心。这个提醒对销售来说是一个温柔的鞭子但实际效果比主管天天去催好得多。我上线两个月后看数据客户跟进率提升了超过三成这是最直观的变化。3.4 权限体系与数据隔离每个角色能看到什么CRM 最敏感的是权限因为它涉及客户资源分配。若依框架本身提供了 RBAC用户-角色-权限三级模型我在这之上重点做了数据权限控制。数据权限我配置了三个级别仅本人数据普通销售登录后只能看到owner_id 自己的客户和商机本部门数据销售主管可以看到本部门所有成员的客户数据方便做团队管理和资源调配全部数据仅管理员可见用于日常运营统计和风险管控。这个设计解决了一个很实际的问题销售之间互不可见避免抢单、撞单管理层又能随时掌握团队情况不用让销售挨个汇报。另外我做了客户转移功能。销售离职或调岗时管理员可以把他名下的客户批量转给其他销售并保留历史操作记录。3.5 合同、回款与报表统计最终闭环要看钱客户管理不只是“拿下客户”还要能收到钱。所以 DeskcommCRM 打通了合同和回款。合同表有contract_no、customer_id、amount、sign_date、status执行中、已完成、已终止。回款表有contract_id、pay_amount、pay_date、pay_status。两张表通过合同 ID 关联一个合同可以有多笔回款。有了这些基础数据报表才真正有料。我最常用的是三个报表销售漏斗图根据商机阶段统计数量和金额看哪层转化率最低员工业绩排行按人员统计合同金额和回款金额按时间筛选客户来源分析按source字段聚合客户数评估哪种渠道来的客户质量更高。报表 SQL 也没想象的复杂比如按人员统计商机金额就是select owner_id, sum(amount) as total_amount from crm_business where status not in (流失作废) group by owner_id order by total_amount desc;但要注意报表页不要实时去查业务表数据量大以后会拖慢系统。我当时的处理是每天凌晨定时把关键指标汇总到一张统计表里报表页面只查统计表查询速度基本秒开。4. 部署上线让 CRM 变得“永久在线”的实操全过程开发完成之后最难啃的就是部署。CRM 的价值在“随时能用”所以部署的核心诉求是公网可以访问、宕机能自动拉起、数据丢了能恢复。下面把我在部署 DeskcommCRM 的完整流程和配置贴出来照着走基本能通。4.1 服务器和域名准备一台 2 核 4G 起步服务器选型我建议最低 2 核 4G磁盘 40G 以上。系统选 CentOS 7.9 或 Ubuntu 20.04 LTS 都行我个人是用 CentOS 7.9习惯用systemctl和firewalld。域名准备一个二级域名比如crm.yourdomain.com然后在云控制台解析到服务器公网 IP。解析生效可以ping确认或者用dig crm.yourdomain.com看返回的 IP 是否一致。服务器买好后第一件事不是装环境是先改系统默认端口和防火墙规则。只放行 22、80、443其他端口一律关闭。MySQL 的 3306 端口尤其不要对外网开放否则会被反复扫描爆破。如果确实需要远程连数据库做维护建议通过 SSH 隧道连而不是直接暴露端口。4.2 后端编译打包与数据库初始化在本地开发环境执行mvn clean package -DskipTests打包完成后deskcomm-admin模块的 target 目录下会生成一个可执行的 jar 包。把这个 jar 包上传到服务器比如放到/opt/crm/目录。数据库这边先在服务器上把初始化 SQL 脚本执行一遍。这里有个容易踩的坑本地 MySQL 版本和线上版本不一致导致导入 SQL 后出现排序规则或字符集问题。我用的办法是线上创建完库之后导入前先进库执行ALTER DATABASE deskcomm CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;再导 SQL基本能避免乱码。后端配置文件里要改的地方包括数据库地址、账号密码、Redis 地址和密码以及一个自定义的接口前缀路径。正式环境一定要把默认的管理员密码改掉这个真的是老生常谈但每次都能发现有系统栽在这上面。4.3 Nginx 反向代理和 HTTPS访问入口的关键后端是 jar 包的嵌入式服务默认监听 8080 端口。前端是打包后的静态文件由 Nginx 提供服务。如果不想让用户直接访问 8080需要用 Nginx 做一层反向代理。我的 Nginx 配置大概是这样的server { listen 80; server_name crm.yourdomain.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name crm.yourdomain.com; ssl_certificate /etc/nginx/ssl/crm.yourdomain.com.pem; ssl_certificate_key /etc/nginx/ssl/crm.yourdomain.com.key; root /opt/crm/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }这里有几个关键细节location /api/里的/api/和后台接口前缀必须匹配如果你后端配置的接口前缀是/prod-api/就写成location /prod-api/然后把proxy_pass后面的地址改成http://127.0.0.1:8080/try_files $uri $uri/ /index.html;必须写否则前端刷新页面时会 404HTTPS 证书申请好后要配置自动续期我是在服务器上加了个定时任务每个月跑一次续期脚本。4.4 进程守护与开机自启别让 Java 进程悄悄死掉用java -jar启动的服务有一个问题窗口一关服务就没了进程异常退出也不会自动重启。所以我用 systemd 来做进程守护写一个 service 文件[Unit] DescriptionDeskcommCRM Service Afternetwork.target [Service] Userroot WorkingDirectory/opt/crm ExecStart/usr/bin/java -Xms512m -Xmx1024m -jar /opt/crm/deskcomm-admin.jar --spring.profiles.activeprod Restartalways RestartSec10 [Install] WantedBymulti-user.target把这个文件放到/etc/systemd/system/deskcomm.service然后执行systemctl daemon-reload systemctl enable deskcomm systemctl start deskcomm这里Restartalways非常关键进程崩了systemd 会在 10 秒后自动拉起来确保 CRM 的“永久在线”不只是嘴上说说。4.5 数据备份与恢复演习备份不只是跑个脚本数据是 CRM 的生命线没有备份等于裸奔。我写了一行 crontab 定时备份0 2 * * * mysqldump -u用户名 -p密码 deskcomm | gzip /backup/deskcomm_$(date \%Y\%m\%d_\%H\%M\%S).sql.gz定时任务是写了但我后来发现最关键的问题是“备份了但从没验证能不能恢复”。有一次同事问我“如果数据库挂了怎么办”我说“有备份啊”结果一练还原发现备份文件是空的。从那之后我定了一条规矩每个季度至少做一次恢复演练在测试库上把备份导一遍确认数据完整可用才算数。备份文件不要和数据库放在同一台服务器上否则服务器宕机或磁盘损坏时备份也没了。建议把备份同步上传到对象存储里或者至少拷贝到另一台机器。5. 邀请员工、日常运维中的常见问题与排查技巧系统上线之后真正的挑战才刚开始尤其是团队陆续使用过程中的各种日常坑。下面这些问题是我在运营 DeskcommCRM 的这段时间里真实遇到并解决的整理出来方便大家参考。5.1 像飞鱼 CRM 一样“邀请员工”在自建系统里怎么做经常有人拿飞鱼 CRM 的“邀请员工”功能做对比问自建系统怎么实现。自己部署的系统逻辑其实更直接不需要发邀请邮件管理员在“用户管理”里新增账号即可。我推荐的操作流程是在“部门管理”里先把组织架构建好比如销售一组、销售二组在“用户管理”里新增用户填写账号、姓名、手机号设置初始密码给用户分配角色比如普通销售、销售主管、管理员在数据权限里设置这个角色能看到哪些数据这一步容易被忽略但不配就会导致新员工登录后看不到任何客户如果需要把线索池或某个销售名下的客户批量转移给新员工。有一个体验细节值得注意新增用户时如果给了初始密码建议在系统设置里开启“首次登录强制修改密码”避免长期使用初始密码带来的安全风险。5.2 公网访问不稳定的常见原因排查系统上线后在公网访问出问题是最让人头疼的。我把遇到过的几个典型问题和定位思路整理成一张排查表现象可能原因排查方法域名打不开域名解析未生效ping crm.yourdomain.com看 IP 是否正确域名能开但页面没响应后端服务未启动systemctl status deskcomm看进程状态页面出来了但接口报 502Nginx 反向代理地址配置错误检查proxy_pass地址和端口端口不通云安全组未放行 80/443登录云控制台检查安全组入方向规则JAVA 进程频繁掉内存不足进程被 OOM 杀free -h查看内存必要时调大-Xmx页面打开很慢MySQL 未建索引SQL 慢开启 MySQL 慢查询日志定位慢 SQL还有一个经常被忽略的点服务器的系统盘满了日志文件把磁盘塞满服务会变得异常卡顿甚至拒绝连接。建议定一个日志轮转策略或者用logrotate自动切割日志文件。5.3 重复客户数据与 Excel 导入报错上线后销售批量导入客户最容易出现重复数据。我在设计客户表时给phone加上唯一索引从数据库层面堵住并发场景下的重复插入但业务上只靠数据库不够因为客户手机号可能为空所以新增客户时还要做一层“手机号非空时查重”的提醒。至于 Excel 导入报错常见原因有三个模板表头和系统要求不一致比如模板要求phone表头写成了“联系方式”日期格式不对报“日期解析错误”导入前确保单元格格式是文本或标准日期手机号被 Excel 自动转成科学计数法这个我踩过导入前选中列设置成“文本”格式再复制数据。5.4 定时任务、时区与提醒不生效DeskcommCRM 里“下一次跟进提醒”依赖定时任务但我们上线后第一天早上没有收到任何提醒排查了好久发现是服务器时区问题。CentOS 默认时区可能是 UTC和北京时间差了八小时早上八点的定时任务实际跑的时候已经下午四点了。解决办法timedatectl set-timezone Asia/Shanghai再确认 Java 进程的 JVM 时区可以在启动脚本里加上-Duser.timezoneAsia/Shanghai免得系统时区改好了但 Java 还用旧时区。另外一个提醒是定时任务扫描的是“未来三天内到期且未完成”的跟进记录如果销售已经录了新的跟进记录记得在写定时任务逻辑时把最近一条跟进记录的next_follow_time更新掉不然旧的到期提醒还会不断弹出来用户会觉得很烦。最后再分享一点实际使用中的体会整套 CRM 上线跑了几个月之后我最大的感受不是功能多么炫而是“流程顺了协作成本明显降低”。以前销售交接客户要整理表格现在直接转归属人以前管理层想了解销售进展只能开会听汇报现在打开报表一眼就能看到每个商机卡在哪个阶段。工具本身不会自动卖货但它能把人从“反复催问”里解放出来去做真正有价值的客户沟通。如果你正准备搭一套自己的客户管理系统我的建议是先别追求大而全第一版能把客户、线索、跟进记录这三个模块跑顺就已经赢了大多数团队。DeskcommCRM 下一步我打算把移动端体验再优化一下同时扩展报价单和工单模块一步步来比什么都重要。