SpringBoot+Vue.js客户关系管理系统毕设源码全解析
搞毕设的那段时间最崩溃的不是写代码而是拿着SpringBootVue.js的客户关系管理系统源码却没有头绪。这套项目是一套完整的Java Web毕设解决方案里面包含了完整项目源码、SQL脚本、接口文档前端是Vue.js做页面后端是SpringBoot写接口数据库用MySQL典型的前后端分离做法。它解决的核心问题就是让一个没有任何CRM业务经验的学生能在尽量短的时间内把系统跑起来并且理解每一个模块为什么这么设计。在决定写这套系统之前我先说下它适合谁。如果你是Java Web方向的毕业生正在为选题发愁或者已经选了CRM这个方向但不知道代码结构怎么组织这套项目会给你一个非常完整可落地的参考。如果你是在做课程设计想找一个界面好看、功能齐全的案例它的前端页面基于Element UI打开就有现代后台管理系统的样子。如果你只是想找一段能交差的代码直接照抄它也符合这个需求但我更建议你把它当学习材料来用跑通之后再自己改几个模块这样答辩的时候才不会被问倒。1. 项目整体定位与业务设计1.1 客户关系管理系统到底解决什么问题很多人第一次看到“客户关系管理系统”这名字会觉得它不过就是一张客户信息表做增删改查。实际上CRM的核心价值是把销售过程管理起来而不只是记录数据。这套系统里围绕客户做了一整条业务闭环从线索录入到联系人绑定、跟进记录沉淀、商机推进最后到合同签约和回款统计每一步都有对应的数据支撑。对于毕设来说“业务闭环”这四个字特别重要它决定了你的系统像不像一个真正能用的产品而不是堆了一堆功能页面却各不相干。系统里最核心的角色是销售人员和销售主管。销售人员每天打开系统要能快速看到自己名下的客户列表、今天要跟进的客户、待处理的合同。销售主管关注的则是整体业绩数据新增了多少客户、哪些渠道贡献的线索最多、每个销售人员的跟进频率和转化情况。因此在功能设计上我把首页做成一个工作台把当天重点数据直接铺出来而不是把所有入口都藏在左侧菜单里。这种从业务场景出发的设计在答辩时也是特别好讲的切入点。除了首页工作台系统还包括客户管理、联系人管理、跟进记录、合同管理、数据统计、系统管理等几大模块。客户管理负责客户的增删改查和分配联系人管理处理一个客户下的多个联系人跟进记录用来沉淀销售每次沟通的内容合同管理把成交结果落成数据数据统计则是从客户来源、成交金额、跟进次数等维度生成报告系统管理负责用户、角色和菜单权限。把这些模块串起来看你会发现它们不是孤立的功能点而是一条完整的销售业务链路。我拿一个具体场景来说明销售小张登录系统后在首页看到今天有3个“待跟进”客户。他点开第一个客户客户档案里能看到这个人的行业、来源、级别和过往全部跟进历史。他刚打完电话在跟进记录里写了一条“客户对报价仍有疑虑计划下周再沟通”并设置了下一次跟进时间为下周一上午。当天下午小张又把客户状态从B级调整为A级表示意向度提升。几天后客户同意签合同小张在合同模块里录入一条合同记录金额、签约日期、回款状态都有。到这里一次完整的销售动作就在系统里闭环了。说得直白一点CRM的价值就在于把销售脑子里记的事情全部变成了可查询、可统计、可管理的数据。1.2 为什么偏偏选SpringBootVue.js这套组合选技术栈这件事在毕设选题时就要想明白不然后面会反复折腾。SpringBoot负责后端接口Vue.js负责前端页面两者加起来正好组成一套主流的“前后端分离”开发模式。选SpringBoot的直接原因是它把以前SSH、SSM里那些繁琐的配置全包办了。比如你想用MyBatis做持久层加一个starter依赖写几行配置就能跑想生成接口文档集成Swagger也只是加依赖和注解的事。对于毕设来说这意味着大量时间可以省下来去写核心业务代码而不是耗在xml配置文件上反复排查。Vue.js这边的好处是组件化开发。每个页面可以拆成独立的组件客户列表是一个组件新增表单是一个组件跟进记录时间线是一个组件开发的时候脑子特别清晰改代码也不容易把别的逻辑碰坏。再配上Element UI组件库表格、弹窗、表单、分页器全是现成的界面做出来至少是“能看”的水平。对于缺少前端美工经验的学生来说这套组合几乎是最优解不需要自己写复杂的CSS又能把页面做得整齐统一。当然前后端分离也有代价。它意味着你要处理跨域问题、打包部署问题、前后端联调问题。这些麻烦在毕设环节其实是加分项因为老师随便问两句你只要能说出“前端代理打个/api、开发时启动两个服务、上线时把dist打进static里”基本就能证明你是真正写过这套系统的。反过来如果全程都用模板引擎写在一个SpringBoot项目里虽然省事但技术陈旧答辩时亮点少很多。所以我的建议很明确毕设优先选SpringBootVue.js这种主流组合它带来的麻烦都是可控的带来的收益却很大。2. 数据库设计与SQL脚本解读2.1 核心数据表怎么设计才合理数据库设计是整个项目的地基大部分毕设翻车都是从表设计没想清楚开始的。这套CRM项目我设计了一张用户表、一张角色表、一张用户角色关联表以及客户表、联系人表、跟进记录表、合同表。权限这块没有做太复杂就是最朴素的基于角色的控制用户登录后根据角色决定能访问哪些菜单和接口。先看用户表。字段包含用户ID、用户名、密码、真实姓名、手机号、角色标识、状态。密码这里我建议不要明文存储至少用MD5加随机盐或者直接用BCrypt。很多毕设项目密码都是明文答辩时老师一旦问起安全隐患就是减分项。加个加密处理代码量不大说出来却是一个亮点。重头戏是客户表字段里至少要包括客户名称、所属行业、客户来源、客户级别、负责人ID、状态这几个。客户来源做成字典类型比如线上广告、朋友转介绍、老客户复购等后面统计报表才能按来源分组。客户级别对应销售跟进优先级常规做法是A/B/C/D四级A级意向度最高、要优先跟进。负责人ID指向用户表代表这个客户当前归哪个销售管这就是最简单的客户分配机制。联系人表挂在客户表下面一个客户可以挂多个联系人。这里有两个容易被忽略的细节一是联系人表要有客户ID做逻辑外键二是删除客户时联动删除联系人和跟进记录否则系统里会残留一堆查不到父记录的数据。跟进记录表是CRM的灵魂记录了每次沟通的时间、方式、内容摘要、下次跟进时间。我特别强调一下“下次跟进时间”这个字段很多新手会忘掉它但它恰恰是系统里最有价值的东西。首页的“今日待跟进”列表就是根据这个字段筛选的统计报表里的跟进次数也是从这张表聚合出来的。合同表负责成交落地字段主要有合同编号、合同金额、合同状态、签约日期、关联客户ID。到这里从客户到合同的数据链路彻底打通数据库设计也就能站得住脚了。2.2 SQL脚本导入与初始化时容易踩的坑拿到SQL脚本第一件事不是直接导入而是先确认数据库版本和字符集。我这份脚本默认适配MySQL 5.7和8.0库名统一用crm_db字符集是utf8mb4。导入方式很简单用Navicat或者命令行source命令都行但注意导入时不要覆盖掉你本地已有的同名数据库最好先备份。MySQL 8.0和5.7在时区处理上有差异。如果你在SpringBoot连接串里没有配置serverTimezone可能会遇到启动正常但一查询时间字段就抛异常的情况。解决办法是在jdbc连接URL末尾加上?serverTimezoneAsia/Shanghai。另外如果数据库是8.0驱动依赖建议用mysql-connector-j老版本驱动虽然也能连但可能会有SSL警告看着心烦反正不影响功能。SQL脚本里我写了演示数据。如果业务需求特殊想清空重来可以执行脚本里的DELETE语句但要注意自增主键最好配合TRUNCATE或者重置自增列否则新增的数据ID会从原来的最大值继续往下走。演示数据和筛选条件要对得上这一点很容易忽略。脚本里我特意把客户来源、行业、级别这些字典值填得比较规整就是为了演示时筛选不会因为数据缺失而出现空白结果。建表语句有几个关键点比如客户表常用的核心字段大概是这个样子CREATE TABLE crm_customer ( id BIGINT AUTO_INCREMENT PRIMARY KEY, customer_name VARCHAR(100) NOT NULL COMMENT 客户名称, industry VARCHAR(50) COMMENT 所属行业, source VARCHAR(50) COMMENT 客户来源, level VARCHAR(10) COMMENT 客户级别 A/B/C/D, owner_id BIGINT COMMENT 负责人ID, status TINYINT DEFAULT 1 COMMENT 状态 1启用 0停用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_owner (owner_id), KEY idx_level (level) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT客户表;还有一点建表顺序不能乱。外键约束是强关联时必须先建主表再建子表否则外键指向的表不存在导入会直接报错。如果你后续要改表结构也尽量用ALTER语句而不是删了重建这能省掉大量不必要的麻烦。脚本里我把外键约束写得比较宽松保留了逻辑关联但不强制物理外键这样在演示增删数据时会方便很多报错概率也低。3. SpringBoot后端核心实现3.1 四层代码结构与统一返回结果怎么组织后端代码我采用经典四层结构Controller、Service、MapperDao、Entity。为了代码更规范我额外加了DTO和VO层DTO用来接收前端传参VO用来给前端返回数据。新手可能觉得层数越多越麻烦但真正开发起来就会发现前端调接口时参数经常变如果都怼在Entity上改的时候到处都要跟着动非常痛苦。加上DTO这一层前端参数怎么变后端只需改一个接收对象即可。Controller层只负责接收HTTP请求和参数校验不写任何业务逻辑。Service层写核心业务逻辑比如保存客户前检查有无重复名称、删除客户前检查有没有未完结的合同。Mapper层只对接数据库SQL写在Mapper.xml或注解里。这样分层的好处是你拿到项目源码后定位问题特别快日志里看到一个异常顺着Controller→Service→Mapper一层层往下找就行不会出现一个类几千行、改一行崩一片的情况。这里我要重点讲一个习惯统一返回结果封装。项目中写了一个Result类泛型接口code表示状态码message表示提示信息data放具体数据。例如public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.setCode(code); result.setMessage(message); return result; } // 省略getter/setter }所有Controller统一返回Result前端用响应拦截器统一判断code登录过期、无权限这类全局情况都能在拦截器里统一处理。如果你一开始就把接口返回写成五花八门的结构后面前端联调时就知道有多痛苦了。不是吓唬人我在实际项目中见过接口返回三四套不同格式的代码前端同学写起来每敲一个接口都要重新看一遍数据结构。登录认证这块用的是JWT而不是传统Session。用户登录成功后后端算出一个带有效期的token返回给前端保存。前端每次请求都带上Authorization请求头后端通过拦截器统一校验token有效性。这种方式的好处是无状态、服务端不需要保存会话数据多台服务器部署也不会出问题。毕设系统规模虽然不大但用JWT能体现你对现代接口鉴权方式的理解属于性价比很高的技术亮点。3.2 接口文档里到底有什么怎么快速联调接口文档是这套源码包里非常重要的一部分开发时我和前端同学联调几乎全靠它。文档主要包含每个接口的请求方式、URL、请求参数、返回示例以及常见的错误码说明。我按业务模块整理成表格核心接口大概有这些接口功能请求方式地址登录POST/api/auth/login获取当前用户信息GET/api/auth/info分页查询客户列表GET/api/customer/list新增客户POST/api/customer/add编辑客户PUT/api/customer/update删除客户DELETE/api/customer/delete/{id}查询客户跟进记录GET/api/follow/list/{customerId}新增跟进记录POST/api/follow/add分页查询合同列表GET/api/contract/list首页统计接口GET/api/dashboard/statistics接口文档的呈现有两种方式。一种是集成Swagger在线生成API列表麻烦在于SpringBoot 3.x出来之后旧版Swagger依赖和新框架之间出现了兼容问题。另一种是写一份Markdown接口文档随源码包一起发布方便打印出来当答辩材料也方便在不能开开发环境的时候快速查阅。我两个都保留了Swagger用于日常开发Markdown文档用于最终交付。联调时我建议配合Postman或者Apifox使用。先在接口管理工具里把登录接口跑通拿到token再设置全局请求头之后测试客户列表、跟进记录、合同这些业务接口就会顺畅很多。接口文档里我还标注了每个接口在什么情况下会返回什么错误码。比如参数校验失败返回400用户未登录返回401无权限返回403。前端写响应拦截器时有这些状态码约定处理起来就非常统一。4. Vue.js前端核心实现4.1 前端项目结构、路由与Axios请求封装前端项目基于Vue框架开发配套使用Vue Router做路由跳转Axios做HTTP请求Element UI作为UI组件库。如果你拿到的是最新版本可能已经换成了Element Plus这取决于Vue版本Vue2配Element UIVue3配Element Plus这个对应关系一定要搞清楚不然组件全部不显示的时候都不知道去哪查。前端项目结构大致如下src ├── api // 接口请求封装 ├── router // 路由配置 ├── store // 状态管理存放登录信息等 ├── views // 页面级组件 │ ├── Login.vue │ ├── Layout.vue │ ├── customer // 客户模块页面 │ ├── follow // 跟进模块页面 │ └── contract // 合同模块页面 ├── utils // 工具类含request封装 └── main.js // 入口文件在api目录里我把请求封装成一个个函数页面组件不直接写axios。以客户接口为例// api/customer.js import request from /utils/request export function getCustomerList(params) { return request({ url: /api/customer/list, method: get, params: params }) }页面里只需要import这个函数然后调用就能取到数据。好处是接口地址集中管理后端改了地址你只需要改一个文件不用全局搜索。axios还需要封装两层一层是baseURL设置和请求拦截器另一层是响应拦截器。响应拦截器里统一判断code如果发现token失效直接清空本地存储并跳回登录页。这个封装看起来很底层但实际开发中能省下大量重复逻辑。状态管理这里我会在store里存一个用户信息和菜单权限列表用户登录后拉取一次后续页面通过store读取。页面刷新后store数据会丢失所以要用localStorage做持久化重新加载时再从本地恢复。注意敏感信息尽量不要放前端存储至少不要明文存对于毕设而言存一个用户基本信息还能接受密码和token属于高危对象能不放就不放。4.2 客户管理页面的实现思路表格、分页、弹窗客户管理页面是整个前端最核心的页面。页面布局从上到下分成三块顶部是搜索条件栏中间是操作按钮和表格底部是分页器。搜索条件包含客户名称、所属行业、客户来源、客户级别按钮包含新增、编辑、删除、跟进、分配。整个页面的工作逻辑就是围绕这些条件去请求后端接口然后把返回值渲染到表格里。表格展示的字段要和后端返回的字段一一对应。每次查询都走分页接口后端返回total和records两个核心字段前端拿到total设置给分页器切换页码时重新请求数据。分页参数无非是pageNum和pageSize配合搜索条件一起传给后端。这个模式非常固定几乎所有的后台管理页面都是同一个套路学会一个页面后其他模块就能照葫芦画瓢。新增和编辑我用同一个弹窗组件打开弹窗时判断有没有传进来的行数据有就回显表单内容没有就清空。弹窗表单里做了基础校验客户名称必填、联系方式格式校验、行业和来源用下拉选择。校验规则不复杂但能把很多低级错误拦在提交之前减少不必要的接口交互。有一点我特别想提醒编辑回显时要注意数据类型。后端返回的客户级别可能是字符串“A”前端下拉选项的值恰好也是字符串就没问题但如果一个用了数字、一个用了字符串回显时会发现选项永远选不中这是Element UI组件里很常见的问题。其实前端真正繁琐的不是业务逻辑而是各种细节状态。比如新增成功后要刷新列表还是停留在当前页编辑后要不要保持页码删除前要不要二次确认跟进按钮点击后在哪个位置展示时间线。这些细节看起来不起眼加在一起才是一个能用的系统。如果一条一条处理不好演示时页面就显得很生硬老师一眼就能看出来这是个只做了demo的静态页面。4.3 打包部署把Vue打包放进SpringBoot里为了毕设演示方便这套项目提供了两种部署方式。第一种是开发模式本地起两个服务前端npm run serve监听8080后端SpringBoot监听8081前端通过代理把/api转发到后端前后端分离联调。第二种是合并部署执行npm run buildVue生成dist目录然后把dist里的全部文件复制到SpringBoot项目的src/main/resources/static目录下重新打包SpringBoot启动后前后端都在同一个端口上。合并部署有一个好处就是演示的时候只启动一个Java进程。老师或者评审人员要跑你的项目不需要额外安装Node环境步骤非常简单。这种“单文件即可运行”的交付方式在毕设验收时非常加分因为评审人没有耐心看你怎么折腾两个服务。我把详细的打包步骤写在了项目说明文档里核心命令就是npm install、npm run build、mvn clean package。这里有一个高频坑合并部署后页面能打开但一刷新就404或者直接打不开路由。原因通常是Vue Router启用了history模式刷新请求会打到SpringBoot的路由解析上而后端没有对应的资源。解决方法是把Vue Router改成hash模式或者在后端加一个转发规则把非/api的路径都转发到index.html。对于毕设而言hash模式最省事地址栏带个#号无伤大雅功能完全不受影响。我代码里默认用的就是hash模式所以遇到刷新404的同学先检查一下这条。5. 从0到1跑通项目的完整流程5.1 环境清单与版本选择我每次把项目发给别人都会先给一份环境清单。照着装基本不会出大错工具版本建议作用JDK1.8或11运行SpringBootMaven3.6以上依赖管理与项目构建MySQL5.7或8.0数据库Node.js14以上运行前端编译工具IDEA2020以上开发IDE最容易被坑的是Maven。Windows下如果你没配置过镜像下载依赖会慢到怀疑人生。建议在Maven的settings.xml里配置阿里云镜像并把本地仓库地址改成不含中文和空格的目录。我见过不少同学项目启动失败最后发现根本原因是本地仓库路径在中文用户名目录下导致某些依赖写入失败。这个细节很隐蔽但真实存在。Java版本这一点我和很多人的建议一样毕设用JDK 8或11就好没必要追新上17或21。虽然新版JDK性能更好但配套的SpringBoot版本、MyBatis插件、构建插件未必都兼容搜问题时也难以命中别人踩过的坑。选一套成熟稳定的版本组合比选一套最新的技术栈更务实。5.2 后端启动五步走拿到源码后用IDEA以Maven项目方式导入后端代码等待依赖下载完成。依赖下载时间看网速第一次可能需要几分钟到十几分钟中途尽量不要中断否则本地仓库里留下的半成品依赖会让后续每次启动都报错。第一步找到application.yml修改数据库连接信息包括地址、端口、用户名、密码。第二步先执行SQL脚本建库建表再检查一下application.yml里的数据库名是否和脚本中的一致。很多时候启动报错不是代码问题就是库名写错或者漏执行了脚本。第三步启动SpringBoot主类观察控制台有没有打印出启动成功的日志。后端启动成功的标志是端口监听正常访问Swagger地址能看到接口列表。如果日志里出现“Port already in use”说明端口被占用可以在application.yml里修改server.port或者找出占用进程把它关掉。还有一种情况是数据库连接报错这类错误通常会有明确的异常信息比如Access denied或Communications link failure顺着排查就行。后端起不来九成问题出在环境配置而不是源码本身。5.3 前端启动与依赖安装前端项目导入到IDEA或者VS Code都可以。在项目根目录执行npm install。这里同样存在镜像问题建议先把npm registry切换到国内源比如淘宝镜像否则依赖多的时候可能要等很久。依赖安装结束后执行npm run serve启动开发服务器。启动成功后浏览器访问本地地址会自动跳转到登录页。输入管理员账号密码如果能进系统、能看到客户列表、能读出统计数据说明前后端联调已经通了。注意前端启动时如果报“npm install失败”优先考虑删除node_modules文件夹后重新安装。很多时候是网络中断导致依赖包下载不全重装是最快的修复手段。如果启动后页面样式乱了、组件全都不显示先检查项目里是用的Element UI还是Element Plus以及有没有在main.js里正确引入组件库的CSS样式。有些项目把样式文件单独放漏引了就会变成一堆裸标签。这些问题和业务代码无关属于搭建阶段的常规问题。5.4 前后端联调排查顺序跑项目时如果报错我一般按这个顺序排查。第一步看后端日志确认数据库连接是否正常第二步看前端控制台确认接口请求有没有发出去第三步看浏览器Network面板确认请求地址和返回状态码。这个方法几乎能定位所有联调问题。接口404优先检查前端代理配置和后端context-path是否匹配。接口500打开后端日志看异常堆栈十有八九是SQL语句的问题或者代码里空指针。登录失败检查密码加密方式是否一致如果后端用了MD5加盐前端传明文时后端必须做同样的加密处理否则永远提示密码错误。我还遇到过一种很隐蔽的情况前端请求地址写死了完整域名走了代理转发之后又去请求另一个域名导致联调时数据加载不出来。遇到这种问题把请求地址全部改成相对路径再在代理里统一加/api前缀就会好很多。如果网络请求连不上先单独用Postman调后端接口确证后端没问题再回头看前端可以快速缩小问题范围。6. 踩坑记录与答辩准备锦囊6.1 毕设开发里那些常见坑开发这套系统时我自己也踩过不少坑挑几个印象最深的分享出来。第一个是SpringBoot版本挑高的问题。现在新创建的项目IDE可能默认生成SpringBoot 3.x但3.x版本和很多老教程、老依赖不兼容比如前面提到的Swagger、某些MyBatis插件版本。如果你只想稳稳地完成毕设SpringBoot 2.7.x几乎是最稳妥的选择网上教程多遇到问题一搜就能找到答案。第二个是跨域问题。前端8080访问后端8081时浏览器会拦截跨域请求导致接口在前端控制台报CORS错误。解决办法要么后端加跨域配置类要么前端用代理转发。我更推荐前端代理因为合并部署的时候根本不存在跨域问题开发环境能跑通就行。如果你两个前端服务都要演示后端加一个全局跨域配置类也不难十来行代码。第三个是时间字段格式化问题。后端返回的时间默认可能带着时区后缀前端显示出来就是“2025-06-01T10:00:00”这种T字格式很不好看。解决办法是后端在时间字段上统一加JSON格式化注解或者全局配置Jackson的日期格式比如spring.jackson.date-formatyyyy-MM-dd HH:mm:ss。这个细节处理掉之后页面观感提升非常明显。第四个是业务日志和异常处理。刚开始我把日志都打在普通输出上出了问题根本定位不到。后来我在Service层加了logger每个关键操作比如新增客户、删除客户、更新合同都留了一条日志异常处理也统一用全局异常处理器Controller里不写try-catch。这样排查问题的时候直接看日志是哪一层出的错效率高很多。这些代码虽然不直接影响功能但能让你的项目看起来更专业。6.2 答辩时怎么讲这套系统项目做完以后答辩环节比写代码更让人紧张。我建议从这几个角度去准备。老师大概率会问这套系统有哪些角色各有什么权限你要能说出管理员、销售主管、销售人员的区别并指出界面或接口层是如何控制权限的。哪怕是简单到角色表里一个字段控制也要讲出具体实现。第二个高概率问题是客户管理的业务流程是怎么设计的这个问题就要回到开头的业务闭环从客户来源、联系人的添加、跟进的记录到合同签订每一步在哪个页面、哪张表里体现。建议你顺手画一张简单的业务流程图不用很复杂线性箭头就可以展示“线索→客户→跟进→合同”这条链路老师看了就懂。第三个问题是为什么用JWT而不用Session这个问题一定要能讲清楚。JWT是无状态的服务端不需要保存会话便于横向扩展和多端登录但同时你也要能说出它的缺点比如无法主动失效、token存在被盗风险。能主动说出缺点的候选人往往更让老师相信你是真的理解而不是背了两句答案就上场。第四个问题是如果客户量变大了系统怎么优化回答思路可以包括加联合索引、分页查询优化、引入Redis缓存热点数据、读写分离。尤其是客户列表查询要强调在客户来源、负责人ID、客户名称这些高频搜索字段上建组合索引避免全表扫描。再往深一点可以说后续可以引入消息队列异步处理统计报表避免首页统计拖慢响应。能说到这一层基本就超过绝大多数毕设水准了。最后演示的时候建议准备一个小故事串场。比如“客户a是从老客户转介绍来的销售第一次电话跟进后写了跟进记录并设定了明天再联系第二天跟进时判断客户意向很高于是录入了合同在统计报表里可以看到成交金额的同步增长。”把整个数据链路串起来演示比零散地展示每个功能更有说服力也天然地引导老师往你擅长的知识点上去问。我自己带过不少做毕设的同学最后想说一句掏心窝的话源码是给你起步用的不是让你背的。如果你能把这套SpringBootVue.js客户关系管理系统跑通把每个模块为什么这么设计讲明白那这份源码才真正发挥了作用。遇到不懂的模块大胆改一改哪怕只是给客户表加一个自定义字段都会变成你答辩时的底气。祝大家都能顺利走完毕设这段路。