基于Spring Boot与Vue的SRM供应商管理系统开发实战解析

发布时间:2026/10/22 2:41:41
基于Spring Boot与Vue的SRM供应商管理系统开发实战解析 敲定一个SRM项目之前我建议你先想清楚一件事市面上成熟的供应商管理系统不少为什么还要自己用Java、Spring Boot、Vue从头搭一套我的答案很简单——大多数中小型公司的采购流程根本套不进那些厚重产品里与其天天做定制化开发、跟厂商扯皮不如自己掌握一套源码级别的系统想怎么改就怎么改。这篇文章就是基于我自己实际搭建SRM供应商管理系统和采购管理系统的完整经验写的从业务模型到数据库设计从后端接口到前端页面再到上线后踩过的坑全都摊开来讲。适合正准备做这类系统、或者已经做到一半卡在某个环节的开发者参考。1. 项目为什么值得做SRM 业务逻辑拆解1.1 供应商管理的核心不是“管”而是“生命周期”很多刚接触SRM的人会把供应商管理简单理解成“一张通讯录加一个状态字段”这是大错特错。供应商在系统里的状态是流动的从潜在供应商注册、资质初审、样品送检、正式准入到日常下单合作、季度绩效评估、年度淘汰每一个环节都对应不同角色、不同审批流、不同数据记录。我见过不少项目死磕编码规则或者列表样式却没把生命周期状态机设计清楚结果上线之后供应商数据越补越乱运营根本不知道这条记录到底该由谁跟进。我做这个系统时第一件事不是写代码而是先把供应商状态枚举和流转条件画清楚。基础状态我分了六档潜在、待准入、正式、暂停、冻结、退出。每个状态变更都要求有操作记录和附件凭证比如“暂停”必须关联质量扣分记录或严重异常事件。状态机不是摆设它直接决定了谁能看到哪些菜单、哪些字段必须填写、哪些操作会触发消息通知。这套东西理顺了后面的采购流程才有支撑否则你只是做了一个表单系统而已。1.2 采购流程才是数据流转的主干道供应商管理解决的是“跟谁买”的问题采购管理解决的是“怎么买、买多少、多少钱”的问题。两者看起来是两套模块实际上共享同一套主数据供应商、物料、价格、交期、质检标准。我在架构设计时把它们拆成两个工程模块但数据库层面共享同一套核心表因为采购订单一旦生成供应商绩效的数据来源就自动有了不需要重复录入。采购流程我按业务复杂度分了三个层级直接下单、询比价、招标。直接下单针对框架协议内的常规物料系统自动带出历史成交价和约定交期询比价针对金额中等、供应商不固定的采购项支持多轮报价和比价分析招标则走完整的评标流程涉及标书发布、投标文件上传、评标小组打分、中标公示。不要一上来就做全链路招标那是定制化程度最高、争议最多的地方我建议第一版本先把直接下单和询比价做扎实招标模块第二期再上。1.3 选型Spring Boot Vue 的组合到底合适在哪技术选型这件事很多人纠结得不行。我选Spring Boot 2.7 Vue 3不是因为它们最前沿而是因为这个组合在SRM场景里综合成本最低。Spring Boot生态成熟工作流有Flowable、权限有Sa-Token或Spring Security、报表有JasperReport基本想要的轮子都有Vue 3配合Element Plus做后台管理界面组件覆盖率高开发速度远快于React那套需要自己拼装的东西。更重要的是人才和运维。中小型公司内部能接手这个系统的人大概率只会Java和Vue选一个冷门框架就是在给未来埋雷。我见过用Python写后端、用Angular写前端的项目最后接手的人痛苦到直接推倒重来。技术栈的“可维护性”比“先进性”重要十倍这个原则在SRM这类业务型系统上体现得尤其明显。2. 系统架构与工程落地2.1 后端工程结构按业务域切分不按技术层切分很多Spring Boot项目喜欢按controller、service、mapper这种技术层分包项目小了没问题一上规模就乱成一锅粥。我这边用的是按业务域切分的方式每个领域一个顶级包内部再分controller、service、dao、entity、dto。举个实际例子供应商域叫supplier里面放SupplierController、SupplierService、SupplierMapper、SupplierEntity、SupplierDTO采购域叫purchase对应放PurchaseOrderController、PurchaseOrderService。这样做的核心好处是一个需求变更通常只改动一个域内的文件不会在多个技术包里来回跳而且新同事入职只需要告诉他“你的需求在哪个域”半天就能摸清代码位置。我维护过那种按技术层分包的遗留系统一个供应商查询功能要改四处地方改完还得小心别把别的业务改坏那种痛苦我不想再来第二次。工程层面分了四个模块srm-common公共工具、通用返回体、异常处理、srm-system用户、角色、菜单、日志、srm-supplier供应商与资质、srm-purchase采购订单与流程。模块间依赖关系是单向的purchase可以依赖supplier但supplier绝对不能依赖purchase我用Maven的依赖检查插件强制这个边界从机制上杜绝循环依赖。2.2 数据库设计的关键表与关系数据库是整个SRM系统最不能省力的部分表结构没设计好后面每一个功能都要为当初的偷懒买单。核心表我大致分成五组。第一组是供应商主数据。supplier_info保存公司基础信息、统一社会信用代码、联系人、银行账户supplier_qualification表存资质证书证件编号、有效期、附件路径注意资质是要临期预警的所以必须有过期时间字段。第二组是物料与价格。material_info维护物料编码、规格、计量单位supplier_material_price存供应商报价多一条版本号字段改价就是插入新版本而不是覆盖旧记录这是审计溯源的基础。第三组是采购交易。purchase_order_header和purchase_order_item是标准的主从表结构订单头存供应商、总金额、状态订单明细存物料、数量、单价、税率、期望交期。第四组是流程与审批。approval_flow定义流程模板approval_flow_instance记录每次审批实例approval_flow_record记录每个节点操作。第五组是绩效与异常。supplier_performance_score存考核维度分数supplier_abnormal_event存交付延迟、质量不合格等异常记录。主从表设计里有一个细节经常被忽略金额字段要用DECIMAL(18,4)而不是DECIMAL(18,2)因为部分供应商报价有四位小数单价合计时才保留两位。我接手过一个项目就因为金额精度不够对账差了几毛钱财务天天打电话。这种问题不致命但恶心人。2.3 权限模型与多租户考量SRM系统的用户角色比普通后台系统复杂得多因为外部供应商也要登录进来查看订单、填报报价、上传资质。我的权限模型用RBAC基础框架但扩展了两类角色内部角色和外部角色。内部角色如采购专员、采购经理、财务、库存管理员走正常的菜单权限控制外部角色如供应商管理员、供应商业务员只能看到跟本企业相关的数据。供应商的数据隔离我一开始用的是简单的supplier_id过滤后来数据量上来发现不对劲有的接口漏加过滤条件会把A供应商的报价单显示给B供应商严重事故。后来我统一封装了数据权限注解DataScope在SQL层指定“当前登录用户的供应商ID必须匹配”所有涉及供应商数据的查询强制经过这个注解处理才算把口子堵上。做这类系统的朋友我强烈建议权限过滤要在SQL层面做而不是在Service层用内存过滤否则迟早出大问题。多租户要看业务定位如果只是公司内部用单租户就够了如果打算做成SaaS卖给别人用需要在建表时就带上tenant_id并且所有表查询都走租户过滤器。我目前这套是单租户设计因为业务场景是独立的集团公司内部多工厂共用。切莫轻易上多租户那会让缓存、定时任务、文件存储全部复杂化能单租户就先单租户。3. 核心功能模块的代码实现思路3.1 供应商注册与资质审核供应商注册分两种入口一种是由内部采购人员手工录入另一种是供应商通过门户页自助注册。自助注册的关键是防垃圾数据和资质伪造。我在供应商门户端增加了图形验证码、公司名称自动查重、联系人手机号验证注册完成后生成一条“待准入”状态的供应商记录同时给采购部负责人推送待办消息。资质审核这里容易踩坑的点是证书附件校验。文件上传不能只传原始文件名一定要做文件类型白名单校验并且附件路径要随机化存储。我遇到过供应商上传一个伪装成jpg的exe文件虽然服务端限了上传大小但类型校验没做全差点出事。现在的逻辑是文件上传后读文件头判断真实类型扩展名只是辅助参考存到本地磁盘或OSS时用UUID重命名并记录原始文件名到数据库。审核流程我用的是Flowable工作流引擎定义了一个简单的线性流程提交资质-采购初审-部门复核-准入通知。每个节点都有超时配置超时未处理会自动给审批人发提醒邮件。实际用下来Flowable对这种固定链路审批够用了不需要上复杂的动态流设计因为动态流在管理上很容易失控。3.2 寻源与询比价流程询比价模块的数据结构我一直采用主从表询价单头标题、寻源方式、状态、截止时间加询价明细行物料编码、数量、期望交期供应商针对明细行分别报价。报价单同样主从报价格式必须跟询价行一一对应前端用表格批量录入后端用一个批量接口接收明细列表不要设计成一条明细调一次接口那样恶意请求会把服务打垮。比价逻辑放在服务端做。我从数据库一次查出所有供应商报价按“同一物料、多个供应商”纵向比较统计最低价、最高价、平均价、与参考价差额最终生成比价分析表。这里有个业务细节不能只看单价还得看运费、税率、付款账期因此比价表里每个报价行都要记录完整成本项计算综合成本排序否则财务审核时一定打回来要求重做。询比价涉及供应商响应时效所以我在询价单发布时启动了定时任务每天凌晨检查哪些询价单今天截止但尚未报价给未报价供应商发短信提醒。短信通道我接的是常见的第三方短信服务商模板固定发前统一做手机号脱敏存储。3.3 采购订单与合同管理订单生成我做了两种方式一种是从询比价结果直接转订单系统自动带出供应商、价格、交期采购员只需确认数量和收货地址另一种是手工建单适合框架协议下的多次分批下单。转单逻辑是询比价模块和采购订单模块的衔接点接口要确保事务一致性——比价单状态要同步更新为“已下单”订单明细要完整拷贝不能出现一边下单成功一边比价单还是待处理的脏状态。合同管理这块我不建议做得太重。合同电子签需要对接第三方签章平台技术工作量不小周期也长。第一版我用PDF模板动态数据填充生成合同文本展示给业务人员确认最终版导出存档。真正复杂的条款谈判和法务审核业务上根本不会全靠系统解决。系统能做的就是把合同版本管好合同编号、供应商、生效日期、有效期、金额、附件、关联订单再配一个到期前30天的预警提醒实用性已经够高。订单变更又是一个高频场景。供应商说原材料涨价要求改单价仓库说交期延误要求改日期。我的订单变更统一走“变更单”流程不允许直接编辑原订单这样每次变更都有完整审计轨迹。变更单跟原订单关联审批通过后生成一条订单变更记录原订单金额字段不动另存一个“最终确认金额”字段财务结算以这个为准。3.4 绩效评估与供应商协同绩效评估的关键在于指标口径清晰否则各部门吵成一锅粥。我建的考核维度有五个质量来料批次合格率、交付准时交付率、价格同比价格竞争力、服务响应及时性、配合度、合规资质有效性、廉洁记录。每个维度配权重按月打分季度汇总。质量分直接对接质检模块的来料检验数据不靠人工打分交付分对接订单收货时间自动计算也不靠人工填人工打分只保留服务这个维度最大程度减少主观因素。供应商协同门户我做了一块专门面向供应商的页面。供应商登录后能查看自己的订单列表、交货计划、质检结果、对账单、绩效分数并可以在线上传送货单附件。这块页面的权限就是我在2.3节提到的外部角色权限代码实现上跟内部后台完全独立走单独的登录入口页面布局也更简洁因为供应商用户不需要学习复杂的后台操作。4. 前端 Vue 项目实战4.1 页面与组件设计前端我用的Vue 3 Vite Element Plus工程结构按“视图-组件-接口-状态”四层组织。视图层只做页面路由和布局拼装组件层拆分业务组件接口层统一封装axios请求状态层用Pinia管理全局共享数据。页面之间不直接调用对方组件只通过路由跳转带参数防止耦合。比如从采购订单列表点击“查看供应商详情”路由跳转到供应商页面并携带supplierId参数页面内容完全由供应商详情页自己拉取。组件设计上有一类组件值得重点提——详情页抽屉。后台系统最常见的操作是看列表然后点开一条记录看详情。我统一封装了DetailDrawer组件传入一个fetchDetail函数和一组字段配置自动加载数据并渲染表单。供应商详情、订单详情、资质详情全部复用这个组件代码量至少减少三分之一。字段配置包括类型文本、金额、日期、枚举、附件、是否必填、是否只读、后端字段名这样后端加字段时前端只需加一行配置不用另写模板。表格列也做了类似处理。我写了一个ColumnConfig配置数组每个表单一页面的列配置都集中放在一个JS文件里列显隐、排序、格式化的逻辑全部统一。改表头文案不用到每个页面去找改配置项就行。这是我个人比较推崇的做法小团队维护后台系统配置化比写死模板更容易长期迭代。4.2 状态管理与接口联调Pinia在这套系统的使用范围是我刻意收敛的。全局状态只放登录用户信息、菜单权限、供应商切换信息这三类其他数据一律通过接口获取、存在组件局部或页面局部状态里。全局状态泛滥是后台前端性能瓶颈和混乱的根源我见过一个老项目把订单列表存在Vuex里结果多人同时操作数据互相覆盖排查了好几天才找到原因。接口联调阶段我总结了一套必守的约定。所有请求封装统一拦截器请求头自动附带Token响应码非200统一弹错误提示接口返回体固定为{code, message, data}结构分页数据为{records, total, current, size}结构。这些约定要写进项目README前后端各留一份否则联调时前端抱怨后端字段名不一致后端抱怨前端参数格式不对扯皮浪费的时间比写代码还多。为了避免跨域和联调冲突我在Vite配置了开发代理把/api前缀的请求代理到本地后端端口生产环境则由Nginx统一转发。这里有个小技巧后端接口统一用/api开头这样代理配置只写一次前端Axios基础路径也只需配置一次不需要根据环境反复改代码。环境变量用.env.development、.env.production分别维护不要写死在代码里。4.3 权限控制与动态菜单前端权限控制必须跟后端协同不能只做页面按钮显隐因为接口校验才是最终防线。我的实现思路是登录成功后后端一次性返回当前用户的菜单树、按钮权限集合前端把这些数据存到Pinia然后用它动态生成侧边栏菜单。路由表里只有基础路由登录页、404页、布局页业务路由是通过菜单数据递归匹配生成的这样一个新页面接入时不需要手动改路由表。按钮级权限我用自定义指令v-permission指令接收一个权限标识数组判断当前用户权限集合里是否有至少一个匹配项没有就移除该DOM元素。采购订单页面有三个权限点purchase:order:add、purchase:order:edit、purchase:order:audit普通采购员只有前两个采购经理才有审核权限。指令实现简单但效果直观业务人员在使用时明显感知到系统“懂权限”这比单纯隐藏菜单更细致。动态菜单有个小坑菜单是组件递归渲染的不能直接使用Element Plus默认的图标名绑定因为动态加载的菜单数据是字符串得维护一个字符串到组件的映射表。我开始没注意菜单能渲染但图标全部消失后来统一了iconMap对象才算解决。这个问题网上讨论很多但实操时还是会头一次踩到。5. 常见问题与排查技巧实录5.1 数据库连接池被打满系统上线第二周早上九点采购部集中操作数据库连接池直接报Connection is not available异常。一开始怀疑是并发太高查了监控发现峰值只有200并发理论上不该打满。后来定位到问题出在一个供应商列表查询接口代码里用MyBatis-Plus的selectList查出全量供应商然后在Service层做了内存分页一万条数据全查出来再截取20条每个请求占用的连接时间拉得特别长。解决方案很简单改成数据库分页查询分页插件配置好PaginationInnerInterceptor前端传current和size后端返回IPage结构。同时我排查了所有历史代码凡是有“全量查出再处理”嫌疑的地方全部整改。这类问题在开发阶段很难暴露因为测试数据只有几十条生产数据一上来就现原形。我给团队立了个规矩任何列表查询必须分页除非接口注释里明确说明数据量上限低于100。5.2 定时任务重复执行导致重复消息询价截止提醒的定时任务在生产环境出现了同一张询价单发三次短信的情况。排查过程比较曲折先检查任务本身有没有重复注册没问题再查任务调度日志发现任务确实执行了多次。最后定位到原因项目启动时多个实例同时注册了同一个定时任务而我没有配置分布式锁多个实例在同一分钟触发了同一个方法。解决办法是引入一个简单的基于数据库的分布式锁表任务执行前先尝试获取锁拿到锁才执行执行完释放。表结构就三个字段任务名、执行时间、过期时间利用唯一索引保证同时只能有一个实例持有锁。如果你的系统已经上了Redis也可以用Redis的SETNX加过期时间实现类似效果。这种问题多发生在生产环境多实例部署后开发阶段本地单实例根本发现不了。5.3 Excel导出内存溢出采购明细报表导出导到五万行左右直接OOM。原因也很直接我把查出来的数据全部拼成List再一次性写入Excel工具类。五万行×每行二十个字段的对象内存占用不可小觑再加上Vue前端同时渲染服务端一下扛不住了。改成流式导出后问题解决。后端用EasyExcel的write方法配合Sax模型逐行写入不再一次性把所有数据加载到内存前端用Blob接收文件流再用URL.createObjectURL生成下载链接。另外我对导出请求也做了并发限制同一用户同时最多一个导出任务防止频繁点击把服务打爆。导出功能上线前一定要用最大数据量做压测这是经验教训。5.4 前端权限菜单刷新消失用户反馈登录后一切正常一刷新页面菜单就全没了。原因是菜单数据存在Pinia里而Pinia默认是内存存储页面刷新状态就清空。我当时没做持久化刷新后没有重新拉取用户信息和权限菜单页面挂了。修复方案是把用户信息和菜单权限做一个持久化处理。我用的pinia-plugin-persistedstate只对需要持久化的store开启登录信息、权限数据存到localStorage同时App.vue里增加一个初始化校验刷新时从本地存储读数据并校验Token有效性有效就重新加载菜单无效跳回登录页。这里要提醒一点不要把供应商的所有业务数据都持久化到本地只存必要的会话信息避免数据陈旧和存储膨胀。5.5 不同角色看到的采购金额不一致有一次财务反馈采购订单列表页的总金额跟订单详情页的总金额对不上。查了半天发现是前端表格列的金额格式化问题列表页保留两位小数详情页显示四位小数还有一批订单因为单价精度问题明细行的四舍五入导致汇总时有几分钱偏差。这类问题根治办法是统一金额处理口径。后端返回金额统一使用String或者BigDecimal的字符串形式避免前端浮点运算前端展示层定义统一的金额格式化函数全局引用不在页面里散落各自的toFixed调用。同时在数据库层保留明细金额和头表总金额两个字段总金额由订单明细计算得出后反写再与财务复核值比对双向校验避免偏差。写在最后的几句实在话做SRM系统最难的从来不是写代码而是把业务规则抽象成可落地的数据结构和工作流。我最大的体会是一定要让采购业务人员深度参与关键流程设计而不是技术团队闷头开发完了交给对方验收。如果你手上的项目正处于方案阶段先花两到三天去采购部跟岗看看他们实际怎么询价、怎么催货、怎么跟供应商对账你设计的系统会完全不一样。另外这套系统的价值是随着数据积累逐渐放大的。刚开始三个月你可能觉得绩效分析、价格趋势都没什么用但等你积累了一年到两年的历史数据采购决策就有了依据这时候你才真正体会到当初把数据模型设计得清晰、把状态机流程做得规范是多么值得的一笔投入。别因为业务方催得紧就在数据模型上偷懒欠下的技术债后面一定会加倍还。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询