ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

自部署CRM系统实战:从技术选型到部署运维全记录

自部署CRM系统实战:从技术选型到部署运维全记录 做客户管理系统这些年我经常被人问到一个问题“免费的CRM和那种自己搭一个私人的CRM网站到底区别在哪”问的人多了你会发现大家真正纠结的不是功能列表而是数据到底在谁手里、功能能不能改、系统能不能一直用下去。DeskcommCRM就是我从实际业务里折腾出来的一套自部署CRM今天这篇就把它的完整思路、功能设计和踩坑记录都摊开聊一聊。DeskcommCRM定位很清晰花少量服务器成本换一套数据完全自主、能随时二次开发的“永久在线”客户管理系统。它适合小微企业主、销售团队负责人也适合自己接外包项目、需要给客户交付CRM的技术人员。如果你正在“用现成免费CRM”和“自建私人CRM系统”之间摇摆这篇文章应该能帮你把账算明白。1. 项目定位与整体方案设计1.1 免费CRM与自建CRM到底差在哪里先聊一个最核心的问题“免费CRM”和“私人CRM网站”听上去都是CRM本质上却完全是两条路。我自己的理解是免费SaaS CRM卖的是“便利”自建CRM买的是“主权”。用一张表把两者的关键差异列出来直观一点对比维度免费SaaS CRM自建/私人CRMDeskcommCRM这类数据归属存在厂商服务器上导出往往受限数据存在自己的数据库随时完整备份功能边界厂商定义好能用就用不能用就忍代码自己掌握想加字段加页面都行费用结构免费版有用户数/存储/功能限制付费后不便宜前期投入服务器和开发成本后期边际成本低定制能力基本不支持深度定制完全支持二次开发在线保障依赖厂商服务稳定性自己做监控、备份、容灾掌控服务生命周期学习成本上手快但业务适配难部署有点门槛但业务匹配度高很多人在百度里搜“永久在线的CRM网站”其实真正想要的就是“数据自己掌控、7x24小时能访问、别哪天厂商停服了我的客户资料也没了”。SaaS免费版不是不能用而是当你积累了几万条客户数据之后会越来越有一种“寄人篱下”的不安全感。DeskcommCRM从设计之初就要解决这种不安全感。1.2 DeskcommCRM的技术选型思路技术选型这件事我一向主张“不追新追稳”。DeskcommCRM最终选定的技术栈是后端.NET 8C#基于RuoYi-NetCore脚手架改造前端Vue 3 Element Plus Vite数据库MySQL 8.0生产环境/ SQL Server可选缓存Redis 7.x鉴权JWT RBAC权限模型部署Windows Server / Linux Nginx反代为什么选RuoYi体系因为成熟的权限管理、部门管理、字典管理、日志管理这些都是CRM的“地基”没必要自己造轮子。RuoYi的生态里Java版叫RuoYi-Vue.NET Core版是基于RuoYi体系移植的RuoYi-NetCore两者的设计思想一脉相承。我之前做过几个若依系项目对这套代码结构比较熟所以直接拿它打底再把CRM业务模块长出来。这个选择其实很多人在做“Ruoyi Office CRM”这类项目时都会走是一套被验证过的技术路线。至于前端用Vue 3核心原因有两个一是RuoYi-NetCore原生支持Vue3 Element Plus前后端代码风格统一二是Vue3的组合式API在维护复杂表单和客户列表时代码复用性比Vue2时代好太多。配合Vite构建开发热更新快生产构建体积也控制得住。2. 核心功能模块设计与实施要点2.1 客户信息管理从“录入”到“建档”的设计CRM的基础是客户信息但大部分系统把这个模块做成了“表单列表”就完事儿了。DeskcommCRM在客户管理这里重点做了三件事。第一件事是数据字段的“自定义扩展”。不同行业的客户字段差异很大卖设备的要填“设备型号”做服务的要填“服务到期日”搞加盟的要填“意向区域”。我做的方案是在系统字典表里预留了扩展字段配置管理员可以在后台给客户表增加自定义字段不用改代码就能适配业务。这块用到的就是RuoYi里现成的字典管理能力配合一个自定义字段表前端动态生成表单项。第二件事是客户查重。我见过太多销售团队因为两个销售重复录入同一家公司最后撞单吵架。DeskcommCRM在客户保存时做了两级校验一是客户名称的精确查重二是联系电话、统一社会信用代码的查重。查重逻辑放在后端验证前端通过接口提示“疑似重复客户”避免脏数据进库。第三件事是客户归属。每个客户必须有一个负责人同时也支持“公海客户”概念——超过30天未跟进的客户自动掉入公海池其他销售可以领取。这个规则看起来简单但做的时候要注意一个细节掉公海前必须给原负责人发待办提醒不能静默就“抢走”人家的客户。后来我在代码里增加了一个定时任务每天凌晨检查一次跟进时间提前3天、1天各提醒一次这样既盘活了沉默客户又不至于引发内部矛盾。2.2 跟进记录与商机漏斗客户信息是静态的跟进记录和商机漏斗才是CRM的“活水”。跟进记录模块我最初只设计了“填写跟进内容”但实际用下来发现问题很大销售填写的跟进内容千奇百怪有写一句“电话沟通”的有复制聊天记录的后期根本没法统计。后来重构时我把跟进记录拆成“跟进方式、跟进结果、下次跟进时间、跟进内容”四个必填项跟进方式用字典管理电话、微信、拜访、邮件、其他跟进结果用下拉有意向、暂缓、已成交、已流失。这样既能考核销售过程又能自动形成跟进日历Dashboard上可以直接展示“今日待跟进”列表。商机漏斗则把客户从“潜在”到“成交”拆成多个阶段初步接触、需求确认、方案报价、商务谈判、赢单/输单。每个商机关联一个客户、一个负责人、一个预计成交金额和预计成交日期。这样做的好处是月底对业绩的时候不用再去翻聊天记录直接看漏斗每个阶段的商机总金额就知道这个月的盘子有多大。系统里我用一个简单的SQL视图把商机按阶段分组聚合前端用ECharts画漏斗图销售管理层看着非常直观。2.3 数据权限与多部门协作自建CRM和海量免费CRM最大的区别之一就是权限可以精细控制。DeskcommCRM是基于RuoYi的RBAC模型来做权限的但CRM有一个特殊需求除了菜单权限、按钮权限还要有数据权限——也就是“谁能看到哪些客户”。我实现了五种数据权限范围仅本人、本部门、本部门及以下部门、全部数据、自定义。比如普通销售只能看到“仅本人”的客户销售主管能看到“本部门及以下部门”老板看“全部数据”。这个逻辑在代码层面就是给SQL查询自动追加一个数据权限过滤条件RuoYi框架里已经封装了DataScope注解加在Service方法上即可。这里提醒一句数据权限设置千万不能只靠前端隐藏按钮必须后端强校验。我见过有系统前端把“查看全部客户”的按钮隐藏就以为安全了结果别人直接调API就把数据全拿走了。DeskcommCRM里所有客户查询接口都会根据当前登录用户的角色在SQL层面强制追加权限WHERE条件这是底线。3. 从零部署的完整实操记录3.1 环境准备与数据库初始化部署一套自建CRM第一步不是写代码而是把运行环境备齐。我用的是Windows Server 2022你完全可以用CentOS或Ubuntu步骤类似需要提前装好以下组件.NET 8 SDK / Runtime后端运行必需Node.js 18用于前端构建MySQL 8.0或SQL Server 2019生产数据存储Redis 7.x缓存和登录会话Nginx反向代理把前后端串起来可选宝塔面板或者你用命令行操作也行环境装好之后先把初始化数据库脚本执行一遍。DeskcommCRM的init.sql会创建整个数据库结构、默认管理员账号、基础菜单和字典数据。在MySQL里执行mysql -u root -p -e CREATE DATABASE deskcomm_crm DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -u root -p deskcomm_crm init.sql这里强调一下数据库字符集务必用utf8mb4而不是utf8因为utf8在MySQL里存不了emoji和生僻字客户名称里万一有特殊字符保存就会报错。utf8mb4是超集通用性最好这是踩过的实打实的坑。3.2 修改配置并启动后端服务后端项目的核心配置在appsettings.json里需要重点修改三块数据库连接字符串、Redis连接、JWT密钥。{ ConnectionStrings: { Default: Server127.0.0.1;Port3306;Databasedeskcomm_crm;Uidroot;Pwd你的密码;CharSetutf8mb4; }, Redis: { ConnectionString: 127.0.0.1:6379,password你的Redis密码,defaultDatabase0 }, Jwt: { Secret: 请替换成一串足够长的随机字符串至少32位, Expires: 120 } }JWT的Secret一定要改不要用默认值。因为JWT是拿这个密钥来做签名校验的如果密钥泄露别人就能伪造登录令牌。生成密钥最简单的方式是在服务器上执行openssl rand -base64 64复制输出的字符串粘进去。配置改好后在项目根目录执行dotnet DeskcommCRM.Api.dll正常情况下日志会输出监听地址默认是http://localhost:8080。如果没有报错说明后端已经跑起来了。为了让服务在服务器重启后自动拉起我建议用NSSMNon-Sucking Service Manager把它注册成Windows服务避免手动启动nssm install DeskcommCRM.Api C:\path\to\dotnet.exe C:\path\to\DeskcommCRM.Api.dll nssm start DeskcommCRM.Api3.3 前端构建与Nginx反代部署前端是标准的Vue3工程构建过程很常规npm install npm run build构建完成后项目根目录下会生成dist文件夹把里面的静态文件整个上传到服务器的/var/www/deskcomm目录Windows环境就放到对应盘符路径。接下来配置Nginx。我这里的思路是静态文件由Nginx直接托管所有/prod-api开头的API请求反向代理到后端http://127.0.0.1:8080。这样浏览器只访问Nginx一个入口前后端天然隔离。以下是一份可用的Nginx配置server { listen 80; server_name crm.example.com; gzip on; gzip_min_length 1k; gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svgxml; root /var/www/deskcomm; index index.html; location / { try_files $uri $uri/ /index.html; } location /prod-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; } }这段配置里有两个容易被忽略的细节一是try_files $uri $uri/ /index.html;这行解决的是前端路由刷新404的问题。Vue3是单页应用如果不加这条路用户在系统里点击“客户列表”按F5刷新Nginx会去磁盘找一个叫“customer”的目录找不到就返回404。这行配置把所有不存在的路径都fallback到index.html由前端路由接管。这个问题我至少帮三个朋友排查过十有八九是少了这一行。二是location /prod-api/ { proxy_pass http://127.0.0.1:8080/; }注意proxy_pass后面的URI结尾有一个斜杠。这个斜杠会把/prod-api前缀去掉再转发比如请求/prod-api/login会变成http://127.0.0.1:8080/login。如果漏掉斜杠后端收到的路径就会是/prod-api/login接口404。配置完成之后执行nginx -t检查语法没问题就nginx -s reload然后浏览器访问http://crm.example.com能看到登录页就说明部署成功了。如果要用HTTPS强烈建议尤其自建系统暴露在公网时在Nginx配置文件里再加一个443端口的server块把SSL证书路径配上然后把80端口的请求301重定向到HTTPS即可server { listen 443 ssl http2; server_name crm.example.com; ssl_certificate /etc/nginx/ssl/crm.example.com.pem; ssl_certificate_key /etc/nginx/ssl/crm.example.com.key; ssl_protocols TLSv1.2 TLSv1.3; # 其余配置和上面的80端口保持一致 }3.4 首次登录与基础初始化部署完成之后用系统默认管理员账号登录后台。默认账号一般是admin初始密码在init.sql里有第一次登录务必修改密码这个不用多说。接下来按照“部门 - 角色 - 员工 - 数据权限”的顺序做初始化在系统管理里创建部门结构比如“销售一部”“销售二部”“市场部”。创建角色比如“销售专员”“销售主管”“运营管理员”给每个角色分配菜单权限和按钮权限。创建员工账号关联到部门和角色。给不同角色配置数据权限范围销售专员选“仅本人数据”销售主管选“本部门及以下”老板角色选“全部数据”。配置字典管理把跟进方式、客户来源、商机阶段等下拉选项按自己的业务维护一遍。这些基础数据最多半小时就能配完。我建议不要在这步偷懒把部门和角色设计清楚了后面的权限和数据统计才会准确否则后期再改权限模型会非常痛苦。4. 常见问题与排查技巧实录自建系统不是部署完就万事大吉日常运维一定会遇到问题。我整理了DeskcommCRM上线至今遇到的高频问题做成速查表问题现象可能原因排查命令 / 方法解决办法后端启动一闪而过端口被占用或配置文件格式错误netstat -ano | findstr :8080修改配置文件端口或杀掉占用进程页面能打开但登录接口报500数据库连接字符串错误或MySQL未启动查看后端日志多半是SQL连接异常检查用户名密码、数据库地址、网络连通性Redis连接失败Redis未设置密码或密码不匹配redis-cli -a 密码 ping修改Redis配置和appsettings.json保持一致登录成功后菜单不显示角色未分配菜单权限后台系统管理查看角色权限给角色重新勾选菜单树并保存前端刷新页面404Nginx未配置try_files浏览器直接访问子路由看错误在location /里加上try_files $uri $uri/ /index.html;API请求跨域Nginx反代路径不对或后端未开CORS浏览器F12看Network请求URL检查/prod-api代理配置和proxy_pass尾斜杠文件上传失败上传目录权限不足或目录不存在查看日志中的IO异常手动创建upload目录并给写权限定时任务不执行任务调度服务未启用或任务配置错误检查系统任务日志在任务管理里启用定时任务确认Cron表达式下面挑几个值得展开的问题。端口占用问题。我遇到过一次部署新版本时后端进程没完全杀掉dotnet DeskcommCRM.Api.dll启动后立刻报Address already in use。排查方式很简单执行netstat -ano | findstr :8080拿到占用端口的PID然后在任务管理器里结束对应进程或者taskkill /F /PID 进程号再重新启动服务就行。建议大家把启动命令写成一个start.bat脚本里面先执行taskkill /F /IM DeskcommCRM.Api.exe忽略失败再启动服务这样每次更新发布就不用手动清进程。数据库连接超时问题。这个问题在多台机器部署时比较常见。如果数据库和应用不在同一台机器MySQL默认只监听本地需要检查my.cnf里的bind-address同时确认云服务器安全组/防火墙放行了3306端口。用telnet 数据库IP 3306测一下通不通比看一堆日志都快。Redis未授权访问。开发环境Redis可能没设密码但生产环境一定不能裸奔。我建议把Redis绑定内网网卡设置强密码并开启rename-command把FLUSHALL这类危险命令禁掉。在Redis配置文件里加一行requirepass 一个足够复杂的密码然后后端连接字符串里带上密码即可。备份与恢复的实战心得。自建CRM最核心的资产就是数据库里的客户资料和跟进记录。我的备份策略是每天凌晨3点用mysqldump做全量备份保留最近30天再同步到另一个磁盘或对象存储。脚本很简单mysqldump -u root -p密码 deskcomm_crm | gzip /backup/crm_$(date %Y%m%d_%H%M%S).sql.gz find /backup -name crm_*.sql.gz -mtime 30 -delete我特别想提醒的是备份脚本本身要定期“演练恢复”别等到服务器磁盘坏了才发现备份文件是坏的。我每季度会拿一份最新的备份到测试环境做恢复确认数据能完整导回来这个习惯救过我好几次。日志排查。系统日志我接入了Serilog输出到文件并做了按天滚动。排查问题时先看当天的日志文件搜索关键词ERROR或Exception定位到具体堆栈。这么多年的经验告诉我百分之八十的问题在日志里都能直接找到答案比闭着眼睛猜快得多。建议自建系统都提前把日志框架配好不然线上出问题时你会非常被动。5. 二次开发与扩展建议DeskcommCRM最吸引人的地方在于它不是一潭死水而是一个可以随时生长的系统。我在实际使用中又陆续给它加了几个新能力这里分享一些思路。5.1 自定义字段如何加以新增“客户等级”字段为例操作流程是在数据库客户表加一个字段customer_level用SQL执行ALTER TABLE crm_customer ADD COLUMN customer_level varchar(20) DEFAULT NULL;在字典管理里新增字典类型customer_level添加“A级、B级、C级”等字典项。前端客户表单页增加一个el-select数据源绑定字典customer_level。后端实体类和DTO里补上CustomerLevel属性。列表查询里可选地加上筛选条件。整套流程下来一个会技术的内部人员在半小时内就能搞定。这就是自建系统的效率你不需要提工单等厂商排期。5.2 把销售漏斗做成可视化看板我在Dashboard模块中用ECharts的漏斗图展示商机阶段分布配合顶部的KPI卡片显示当月新增客户数、跟进次数、预计成交金额、已成交金额。数据来源就是商机表的聚合统计SELECT stage, COUNT(*) AS cnt, SUM(expected_amount) AS total_amount FROM crm_business_opportunity WHERE is_deleted 0 GROUP BY stage ORDER BY stage_order;看板上线之后销售例会不用再翻Excel直接投屏看实时数据管理层对业务状态的感知速度快了不止一个级别。这个小改动带来的价值远超很多大而全的付费报表功能。5.3 后续可以接的扩展方向企业微信/钉钉消息通知把待办提醒、公海预警推送到手机。客户公海自动化已经实现但可以增加“公海客户领取上限”防囤客。合同与回款管理在商机成交后自动生成合同编号关联回款计划。对接企业邮箱客户邮件自动归档到跟进记录。移动端适配目前是响应式布局重度使用可以再做一套小程序。这些方向没有一个是做不到的区别只在于要不要投入做。这也正是自建CRM最大的底气系统是长在自己手里的它跟随业务一起进化。最后说一点个人的体会。从开始搭DeskcommCRM到线上稳定运行期间踩过不少坑也推翻过几次设计。但如果再让我选一次我还是会走自建这条路。对于一个把客户数据当核心资产的公司来说能用一台服务器换回数据主权和功能自由这笔账怎么算都不亏。如果你也准备搭一套自己的CRM不用一上来就追求功能大而全先让客户管理和跟进记录跑起来用起来再在真实业务反馈中一步步完善。系统会跟着业务一起成长这是最有成就感的事情。
返回列表