
4S店的客户管理说起来就是“销售跟进潜客、售后留住老客”这两件事但真正落地的系统却很少把这套逻辑理清楚。很多店里还在用Excel表格甚至纸质登记本来管客户资料销售离职带走一批客户售后保养该提醒了全靠人工打电话客户体验和门店效率两头都顾不上。这个“基于微信小程序的4S店客户管理系统”项目目标就是把这些线下流程搬到线上用小程序作为客户触点后端统一管理客户档案、跟进记录、预约工单和回访记录让销售、售后、管理者各自看到自己该看的数据。如果你是做毕设、课设或者真想给门店做一套轻量级CRM这篇文章的拆解和实操记录应该能帮你少走不少弯路。1. 需求拆解4S店到底需要管什么1.1 从一条线索到一次交车的完整链路做系统之前先别急着写代码得把业务链条捋清楚。4S店的售前端核心流程是获取线索、分配销售、电话跟进、邀约到店、试驾、谈单、成交交车。每个环节都有客户状态的变化比如“新建线索”“跟进中”“已到店”“已试驾”“已成交”“已战败”。这里最容易踩的坑是把客户状态设计得太简单。我见过不少项目给客户表加一个字符串字段叫status然后就没有然后了。等到写统计报表的时候想查“本月从试驾到成交的平均周期”发现根本没有历史状态流转记录只能干瞪眼。所以设计时要加一张客户状态流转表记录每次状态变更的时间和操作人这样后面做销售漏斗分析才有数据基础。另外线索分配也值得单独设计。现实场景里新线索进来后一般由销售经理手动分配给某个销售顾问或者按展厅排班轮流分配。系统里要支持“待分配池”和“我的客户”两个视图销售经理可以把池子里的线索批量指派给顾问也可以回收长期未跟进的客户。1.2 售后端保养、维修、回访的闭环逻辑售后端的核心不是“录个工单就完事”而是要把车辆维保数据和客户关怀串起来。一台车什么时候该保养、上次换过什么配件、有没有保险快到期了这些信息如果散落在不同人手里售后顾问就没办法在客户进店时快速给出建议。所以车辆档案表非常关键它要跟客户表做一对多关联。也就是说一个客户名下可以有多台车每台车独立记录品牌、型号、VIN码、车牌号、购车日期、上次保养里程、下次保养时间。这部分数据一来方便做保养提醒二来客户换车后再来做保养系统能直接拉出历史维保记录体验完全不一样。回访管理这块很多课设项目会直接省掉但恰恰是4S店特别在意的功能。厂家会考核客户满意度店里也有交车回访、保养回访、维修回访这些固定流程。系统里应该给每台成交车辆生成一个回访任务列表销售或客服完成后填写回访结果有投诉则自动升级到管理层处理。1.3 为什么选微信小程序而不是App选型的时候一定会纠结为什么不用App或者H5我当时的判断很简单第一4S店客户基本都有微信小程序扫码即用不需要下载安装获客门槛低很多第二小程序有微信消息订阅能力保养提醒、优惠活动通知可以直接触达客户第三开发成本比App低得多一套代码前后端分离管理后台用Web客户和员工用小程序省事。但小程序也有局限最典型的是包体积限制和用户信息授权规则。比如用户昵称和头像以前wx.getUserInfo就能拿到现在改成了只能拿到默认头像和“微信用户”这个默认昵称必须让用户主动填写或者通过其他方式获取。这类边界问题开发前就要有预期不然做到一半卡住了很影响节奏。2. 系统架构与技术选型2.1 整体架构小程序端加Spring Boot后端这个项目我采用的是标准的前后端分离结构。小程序端用原生微信小程序开发后端用Spring Boot搭建RESTful API数据库用MySQL鉴权用Token机制文件存储用本地目录加Nginx映射。整套技术栈没有引入太重的东西对课设和实际落地都比较友好。后端项目结构我是这样组织的src/main/java/com/example/crm ├── controller // 接口层 ├── service // 业务逻辑层 ├── mapper // MyBatis数据访问层 ├── entity // 数据库实体 ├── dto // 接口传输对象 ├── config // 配置类拦截器、跨域、微信参数 ├── utils // 工具类JWT、时间处理 └── common // 统一返回结果、异常处理这里想特别说一下统一返回结果。刚开始我偷懒每个接口返回什么结构随手写结果前端对接的时候校验状态码得写一大堆分支。后来改成统一的Result对象所有接口都返回{code: 0, message: success, data: xxx}前端只用判断code是否为0清爽很多。数据库连接池用Druid分页用PageHelperORM选MyBatis-Plus。为什么不用JPA说实话MyBatis-Plus在复杂的多表查询和SQL调优上更可控而且生成CRUD代码快适合这种业务逻辑比较重的管理系统。2.2 角色权限四种身份四种视图权限设计是管理系统绕不开的环节。这个项目主要有四类用户系统管理员、销售顾问、售后专员、C端客户。管理员在小程序端也要能做审批操作所以小程序端实际上是一个多角色入口根据登录人身份渲染不同的菜单。我用的方案很简单用户表加一个role字段后端用拦截器校验Token里的角色码前端根据角色码控制页面显示。小程序端没有复杂的路由守卫就在每个页面的onLoad里检查一下全局storage里的角色信息不符合的直接跳转首页并提示无权限。下拉菜单的权限控制粒度到按钮级别比如销售顾问只能看到“新增跟进”“编辑客户”按钮经理能看到“查看全部客户”“重新分配”按钮。这部分用简单的v-if就能实现不用上太重的权限框架。2.3 数据模型设计五张核心表整个系统我实际建了十几张表但核心的业务表可以浓缩为五张客户表、车辆表、跟进记录表、服务预约表、回访记录表。建表的时候有几点提醒客户表不建议把所有信息塞在一张表里。联系方式、身份信息、地址备注这类字段可能有多个比如一个客户家里两台车、两套联系方式分开建关联表更灵活。另外客户表和用户表微信openid绑定表要做区分用户表管登录客户表管业务两者通过user_id关联。时间字段统一用datetime类型不要用varchar存字符串。之前接手过一个老系统日期全用字符串存排序和区间查询的时候一个头两个大全是坑。状态字段建议用整数枚举而不是字符串比如状态值用0、1、2配合注释说明含义。字符串看起来直观但一有拼写错误就查不出来而且不利于做统计聚合。3. 核心功能实现与实操细节3.1 微信登录与手机号绑定小程序登录流程现在是固定套路wx.login拿到code传给后端后端用code去微信接口换openid和session_key再用openid查用户是否已注册。已注册就颁发Token没注册就返回“未绑定”标记前端引导用户走手机号授权流程。这里要特别注意手机号获取并不是直接调接口返回手机号而是通过button组件的open-typegetPhoneNumber让用户点击授权拿到code后由后端调用微信接口换手机号。这个code是一次性的而且有效期很短建议拿到后马上处理。实际开发中我遇到过一个问题用户拒接手机号授权后前端要能优雅处理不能直接白屏。我的做法是在授权页加一个“暂不绑定先逛逛”的按钮非敏感功能允许游客浏览等用户主动下单或预约时才强制绑定。登录Token用的是JWT有效时间设置为7天。小程序端每次请求在header里带Authorization字段后端拦截器统一校验。Token过期时返回特定错误码前端全局处理跳转登录页。3.2 预约试驾与维保服务预约是这个系统的高频操作我用一张appointment表统一管理试驾、保养、维修三种预约类型。前端页面上用户先选服务类型再选预约日期和门店接着选时间段最后提交。时间段的设计有个细节。直接用字符串存2025-06-29 14:00-15:00虽然直观但是没法做冲突检测。我后来改用整型字段存储用0到47表示一天中的48个半小时槽位比如14:00-14:30对应28。后端校验时查一下目标日期和目标门店下这个槽位是否已满满了就提示用户换时间。每个预约单生成后状态流是待确认、已确认、已完成、已取消。客户提交预约后门店员工端会收到新预约通知确认后客户会收到微信订阅消息。这里要提一下微信订阅消息的限制只能给用户推送他们主动订阅过的消息而且一次性订阅只能推一次。所以我在用户提交预约成功后主动弹出一个订阅授权让用户“允许”接收预约结果通知这样门店确认后才有推送资格。// 预约时间冲突检测的核心逻辑简化版 private boolean isSlotAvailable(Integer shopId, String date, Integer slot) { LambdaQueryWrapperAppointment wrapper new LambdaQueryWrapper(); wrapper.eq(Appointment::getShopId, shopId) .eq(Appointment::getAppointmentDate, date) .eq(Appointment::getAppointmentSlot, slot) .in(Appointment::getStatus, Arrays.asList(0, 1)); // 待确认已确认 return baseMapper.selectCount(wrapper) SHOP_SLOT_LIMIT; }这个接口在项目里还配了一个Redis锁防止并发预约同一天同一槽位导致超卖。虽然单店场景下并发达不到很高但养成这个习惯没坏处。3.3 跟进记录与客户状态管理跟进功能是销售最常用的模块它要解决的痛点是客户聊到哪一步了、上次联系是什么时候、下次什么时候再跟进。我在跟进记录表里存了跟进时间、跟进方式、跟进内容、约见时间、下次跟进时间。前端的小程序端有一个待办列表把“今天该跟进的客户”按时间排序展示。逻辑很简单就是查follow_record表里next_follow_time小于等于今天的记录按客户分组取最新一条。这个功能做出来后销售顾问粘性很高因为它替代了人手记事的流程。客户状态管理我建议用状态机而不是自由文本。系统预置固定状态流转规则比如“新建线索”只能流转到“跟进中”“跟进中”可以流转到“已到店”或“已战败”“已到店”可以流转到“已试驾”或“待跟单”。这样可以防止销售乱填也方便后续做转化率统计。表格设计上客户状态字段冗余在customer表里但状态变更流水另外存一张表。查询客户列表时直接查冗余字段速度快分析漏斗时查流水表数据全。这就是典型的空间换时间思路。3.4 员工端视图与经营数据看板C端客户用小程序查预约、查维保记录但真正高频使用的是员工端。销售顾问登录后能看到自己的客户池、今日待办、本月业绩售后专员看到的是预约工单列表经理和管理员看到的是全店看板。数据看板我是用ECharts在小程序端渲染的主要展示四个指标本月新增线索数、线索转化率、预约到店率、客户满意度评分。这些数据在后端用SQL聚合前端直接渲染不用算。统计接口的SQL我贴一段供参考-- 月度线索转化率统计 SELECT COUNT(DISTINCT CASE WHEN status 4 THEN id END) AS deal_count, COUNT(DISTINCT id) AS total_count, ROUND(COUNT(DISTINCT CASE WHEN status 4 THEN id END) / COUNT(DISTINCT id) * 100, 2) AS deal_rate FROM t_customer WHERE create_time BETWEEN #{startTime} AND #{endTime} AND owner_id #{employeeId}用DISTINCT是因为客户可能有多条跟进记录必须去重用客户ID聚合。这个细节如果忘了统计数字会虚高查问题能查一天。4. 实际开发中踩过的坑与排查思路4.1 接口联调域名校验与真机预览小程序开发有个让新手抓狂的限制真机上request请求的域名必须是HTTPS且在后台配置过白名单。开发阶段可以在开发者工具里勾选“不校验合法域名”暂时绕过但真机预览时这个选项不生效。我第一次做的时候没注意开发者工具里一切正常一用手机扫码就是“request:fail”。排查了半天最后发现是没开HTTPS。后来老老实实给后端配了Nginx加SSL证书并在小程序后台把公网域名加进request合法域名问题才解决。这里给个建议如果局域网调试可以在开发者工具中开启“不校验合法域名”然后用电脑的局域网IP访问后端接口开发效率会高很多。到正式部署时再换成公网HTTPS域名。4.2 用户信息的授权规则变化前几年小程序可以直接调wx.getUserInfo弹窗获取用户昵称头像现在这个接口返回的已经是匿名信息了。头像是一张灰色默认图昵称统一是“微信用户”。如果业务上需要真实昵称头像只能使用新的头像昵称填写能力在页面上放一个button引导用户手动选头像填昵称。我的处理方式比较务实不强制用户填昵称直接用微信手机号绑定后把手机号作为默认称呼显示。昵称只作为选填字段在个人中心里用户可以自己改。对4S店来说手机号比昵称重要一百倍销售打电话联系客户才是正经事。4.3 自定义导航栏与安全区适配小程序页面的导航栏默认样式在不同机型上表现还算统一但如果你想做沉浸式头图就得自己配导航栏。一旦开启了自定义导航栏就必须要考虑状态栏高度。获取状态栏高度用wx.getWindowInfo()胶囊按钮位置用wx.getMenuButtonBoundingClientRect()然后动态计算导航栏高度。网上很多代码直接写死一个高度在iPhone上没问题一到安卓全面屏就错位。最好统一封装一个工具方法每次进页面先调用动态设置样式。我实际测试下来iPhone 13 Pro和某安卓全面屏机型的胶囊位置差了将近20像素如果写死自定义导航栏要么叠字要么按钮点不到。这个适配逻辑建议放到公共组件里所有页面复用。4.4 下拉刷新与列表分页的配合客户列表和预约列表都用到了分页加载。一开始我图省事下拉刷新直接重新请求第一页数据然后替换整个列表。结果快速滑动时会看到列表闪烁体验很差。后来改成用wx.startPullDownRefresh刷新时保留原数据把新数据和原数据做合并去重然后按排序字段重新排。虽然代码量多了一点但体验确实顺滑很多。另外一个隐藏问题是分页加载后页数要往上加不然翻到第二页后下拉刷新只会显示第一页数据。5. 项目心得与后续扩展方向5.1 这个项目的核心设计教训做完这个系统我最大的体会是业务理解比技术选型重要。技术栈再新如果客户状态的流转逻辑没理清统计口径对不上系统做出来也只是个录数据的电子表格。反而是业务链路想透了表和接口的设计水到渠成。第二个教训是涉及到时间、金额、状态这类字段一定要做约束和校验。比如预约时间不能选过去的日期金额不能为负数状态变更要写日志。这些防御性编程看起来很琐碎但正是它们决定了系统能不能真正投入使用。5.2 后续可以扩展的方向这套系统目前已经覆盖了销售、售后、预约、回访几个核心场景真要拿到4S店场景里应用还能扩展不少内容加装微信支付后客户可以直接在线支付维修保养费用省去前台排队结账环节。增加会员积分体系签到、评价、推荐朋友都能获得积分积分可以抵扣保养工时费。对接地图API预约成功后给客户推送门店导航卡片减少找不到路的客诉。管理后台做更细的数据分析比如单车产值、进店频次、流失预警帮助门店发现经营问题。在没接触这个项目之前我总以为客户管理系统就是简单的增删改查。真做下来才明白业务规则和细节处理才是真正的难点。希望这篇文章能帮到正在做类似项目的朋友少踩几个我已经替你踩过的坑。如果你在开发过程中遇到具体问题欢迎在评论区留言交流。