做报价系统的人经常碰上一个尴尬场景:销售在微信里甩三张图纸加一句“客户,这个配置大概这个价”,客户追问两句细节就答不上来了,转头来问技术,技术再看图、再算,来回折腾大半天。我们公司之前就是这样,直到把“报价”这件事从聊天记录里搬进系统,并且把“附图”作为一等公民设计进去,整个流程才算理顺。这篇内容我打算完整复盘一下附图报价系统的设计思路、核心流程、技术选型和落地过程,从需求拆解到表结构、从图片处理到权限审批,全部展开讲。适合正在做报价类系统、CRM或销售协同工具的产品经理、后端和前端同学,也适合想把自己手里那套“能用但难用”的报价流程重做一遍的团队参考。
1. 为什么需要附图报价系统:业务痛点和场景拆分
1.1 没有附图报价的日子:信息断层出在哪
我在做这套系统之前,先花了两周时间去跟销售、商务、技术和车间主管聊了一圈。问下来发现,大家抱怨最多的不是“报价慢”,而是“报完价之后说不清楚”。客户发来一张图纸,销售看不懂局部公差,技术又不在跟前,销售只能把图纸转发给技术,等反馈,再把结果口头转达给客户。这个链条上每一步都有信息损耗。
更麻烦的是图纸本身。客户发来的可能是PDF、CAD转出的图片、手机拍的实物照片,甚至是一张手写草图。这些图散落在微信聊天、邮件附件、U盘拷贝里,系统里只有最终报价金额,没有任何过程依据。三个月后客户来对账,问“当时你们报的BOM里第二个零件为什么是那个价格”,销售自己都翻不到原始图片,更别说还原当时的计算逻辑。
所以这套系统的核心目标,第一条不是“更快出价”,而是“让每一次报价都有据可查、可言、可追溯”。附图不是附件,而是报价单的主线索之一,所有价格明细都应该能挂到某张图的某个区域上。这个定位从一开始就定了,后面所有设计都是围绕它展开的。
1.2 附图报价解决的三个核心问题
我把业务诉求收敛成了三个核心问题,也是系统设计时的三条主线。
第一个是信息完整性问题。一份报价单必须包含客户原始需求(图纸、照片、文字说明)、内部方案(选型、BOM、工艺路线)、价格明细(材料费、加工费、表面处理费、管理费、利润)和商务条件(税率、账期、有效期)。报价单不再是“给客户看的一张纸”,而是贯穿售前到成交的完整信息包。
第二个是协同效率问题。销售发起报价后,技术要审图、采购要核价、生产要看工艺,这些角色不在同一时间、不在同一地点,但必须围绕同一份资料协作。系统里要有一个“任务流转”的概念:谁该处理、处理完流向哪里、超时怎么办,全部显式化。
第三个是版本一致性问题。客户中途改需求是家常便饭,图纸V2、V3来回发,报价也改了四五版。如果没有版本控制,就会出现“客户看的是第三版,内部做的是第二版”的错位事故。系统必须把每一版本的结构化数据保留下来,并支持任意两个版本之间做差异对比。
这三个问题确认清楚之后,我才开始画页面原型和数据模型。很多团队一上来就讨论用什么框架、什么数据库,我建议先花时间把“报价单到底包含哪些对象、这些对象之间什么关系”想明白,后面代码就是水到渠成的事。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体设计与核心流程:从询价到成交的全链路
2.1 端到端流程:一个报价单的生命周期
我们在系统里把报价单设计成一条清晰的状态链路,每一步都有明确的负责人和动作。
整个流程大概是这样的:客户询价进来,销售先在系统里创建一个“询价记录”,把客户发来的所有图纸、照片、文字描述全部上传上去,形成一个“需求包”。系统自动给这份需求包生成编号,比如 RFQ-2024-000123,并创建一条报价草稿。销售把需求包指派给技术审核,技术逐张图确认工艺可行性、标注材料、估算工时,如果有问题就在图上直接画圈标注打回。技术确认完成后,报价单流转到商务核价环节,商务根据BOM和工艺路线填入成本价、建议售价、交货周期。最后销售确认商务条件,生成正式报价单,通过系统自带链接发给客户。客户查看后在线上确认或提出修改意见,系统记录对应用户操作行为,反馈回销售。
这一步的好处是,每个动作都留痕。客户什么时候看了报价、看了多久、有没有放大某张图,系统全部记录,销售能判断客户的兴趣点在哪里。上线后我们发现一个很有意思的数据:客户平均会在“价格明细”那张表上停留15秒以上,看附图的时间反而更短,说明客户最关心的还是价格本身,图纸更多是确认“你报的东西是不是我发的东西”。
2.2 核心业务对象与状态机设计
我画系统架构时先把核心对象拆成了五类,数据结构围绕这五个主对象展开。
第一是客户询价单(Inquiry),它是流程起点,记录了客户是谁、询价来源、需求描述、原始文件列表。第二是报价单(Quote),它是核心单据,包含报价编号、客户信息、产品明细行、价格汇总、商务条款、有效期。第三是图片附件(Attachment),它不属于报价单而是属于“需求包”,可以多对多关联到报价明细行,也可以独立存在。第四是审批记录(ApprovalRecord),记录每一次价格审批的节点、操作人、意见和结果。第五是操作日志(AuditLog),记录谁在什么时间看了报价、改了价格、导出了PDF。
状态机方面,报价单的状态流转是:草稿(Draft)→ 技术审核中(TechReview)→ 商务核价中(Pricing)→ 待销售确认(SalesConfirm)→ 已发送(Sent)→ 客户已查看(Viewed)→ 客户已确认(Accepted)→ 已成交(Won)。另外还有两个非终态:已驳回(Rejected)和已取消(Cancelled),前者可以重新编辑后再次提交,后者直接归档不可改。
技术审核中这个状态我特意拆出来了。很多报价系统把技术审核放在一个弹窗里完成,我们却把它做成了独立状态,原因很简单:图纸审核往往需要跨天完成,销售可能催了三次还没有结果。独立状态意味着系统可以针对它做超时提醒,技术每天上班打开系统第一件事就是处理待审图。
2.3 为什么先做模板草稿再做正式报价
这里分享一个我们走过弯路后得出的经验:系统里一定要区分“报价草稿”和“正式报价单”,两者不要混用,不要用一个“是否已发送”字段来区分。
报价草稿是内部工作区,销售、技术、商务都在上面改,字段可以不全,价格可以乱写,所有中间过程都不对客户可见。正式报价单是快照,首次发送给客户时系统自动生成一个不可变副本,客户看到的是哪个版本,系统里就永久留存哪个版本,任何改动都只能生成新版正式报价。
这么设计的好处有两个方面。一是内部可以放心操作,不用因为担心客户看到半成品而束手束脚。二是审计追溯的时候,正式报价单版本号清晰,不会出现“客户收到的文件里写的价格跟系统里的当前数据不一致”这种情况。我们第一版系统没做快照,客户来问价,销售可以反复修改同一个报价单的金额,结果客户截图投诉,我们查不出到底谁改了,特别被动。后来补上快照机制,问题彻底解决。
3. 图片与附件处理的关键技术细节
3.1 图片处理管道:从原图到缩略图和多版本图
附图报价系统里,图片处理是技术重头戏。客户上传的图纸分辨率差异极大,有手机拍的2000x3000照片,也有工程图导出的高清PNG,还有只有1.5MB但放大后模糊不清的PDF截图。系统不能直接拿原始图给所有端去渲染,否则浏览器直接卡死,移动端加载也慢到不可用。
我们设计了一条图片处理管道,上传后自动执行,核心做了四件事。第一步是格式归一化,统一转成WebP格式,兼容现代浏览器,体积比JPEG小30%左右。第二步是多尺寸生成,分别生成原图(最大边4096px)、大图(1920px)、中图(1024px)、缩略图(256px)四个尺寸,原图用于下载,大图用于在线查看,缩略图用于列表页。第三步是EXIF信息清理,手机照片自带的GPS、设备信息全部剥离,避免隐私泄露,同时统一旋转方向。第四步是水印叠加,在线预览的图统一加内部水印,防止销售把系统里的图直接转发给外部,水印内容是当前登录用户ID后四位和系统时间。
管道跑完以后,图片元数据写入数据库,文件本体存在对象存储里。前端在列表页加载的是256px缩略图,详情页加载的是1024px中图,点击“查看原图”才加载大图,这样首屏性能完全可控。
3.2 OCR识别:从图纸里自动提取零件信息
附图报价系统不是光存图就完了,还要能“看图说话”。客户发来的工程图里,往往带有标题栏、零件序号、材料标注,这些信息如果全部靠人工录入,效率低且容易错。我们接了一条OCR识别链路,识别完成后把结构化数据自动填充到报价明细行。
技术选型上,用过通用OCR服务,也试过本地部署模型,最后采用的是“通用OCR+模版匹配”的混合方案。工程图纸的标题栏位置虽然厂商不同,但有规律可循,比如标题栏通常在右下角,包含图号、图名、材料、比例、重量等字段。我们用模板匹配的方式定位标题栏区域,再用OCR引擎识别区域内文字,准确率能做到95%以上。对于非标图纸,退回通用OCR全图识别,然后通过正则提取图号、材料等关键字段。
这里要给一个具体提醒:图纸里的“4-M6”这种螺纹标识,通用OCR很容易识别成“4-MS”或者“4-M6”,后面的数字经常被丢掉。我们做了针对性的后处理规则,将螺纹代号、粗糙度符号、公差带代号这种工程领域高频实体做了独立的词典匹配,识别完再做一轮校验、自动修正,准确率才上来。不要迷信OCR厂商宣传的通用准确率,落地时一定要针对自己的语料做专项调优。
3.3 附件存储选型对比:本地磁盘、MinIO还是OSS
附件存储方案我们经历了两次替换,第一次从本地磁盘切到自建MinIO,第二次又从MinIO规划迁移到云对象存储。
第一版为了图省事,直接存服务器本地磁盘,图片多了以后问题很严重:单机磁盘撑不住,备份困难,Web层和存储层耦合导致重启服务时文件读写冲突。后来切到MinIO,用Docker Compose在内部服务器部署,分三节点,内网带宽跑满能到2.3GB/s,内网使用完全够用,成本也低。但考虑后期数据量增长和异地容灾的需求,云对象存储才是终态,具备生命周期管理、跨区域复制、静态网站托管等特性,只是内网延迟和费用需要权衡。
如果你们是中小团队,我建议起步阶段直接用云对象存储,不要走自建这条路。原因很简单,报价附件是强持久化数据,丢一张图纸都是事故。云对象存储的11个9持久性、版本回滚和跨区域复制能力,自建方案很难低成本实现。上传时采用预签名URL直传,服务端只负责签发凭证,流量不经过应用服务器,避免上传大图时把业务线程池占满。
4. 数据模型与版本管理设计
4.1 核心表结构设计
数据模型我按领域对象拆分,核心表包括客户询价单表、报价单表、报价明细表、图片附件表、报价单附件关联表、审批记录表和操作日志表。这里重点说报价单和图片附件之间的关联设计。
报价单表我用单表存储业务主数据,字段不展开说了,关键字段包括:报价单号、客户ID、销售ID、技术审核状态、商务核价状态、当前版本号、正式版本快照JSON、整体折扣率、税率、总金额、币种、有效期、状态。其中正式版本快照JSON尤其重要,首次发送给客户时,系统会把整套报价数据序列化后存到这个字段,后续改价不影响已发送快照,查询历史版本直接读这一列,速度远快于还原多张表的操作。
图片附件表独立存储,字段包括:附件ID、所属需求包ID、原始文件名、文件大小、加密哈希值、存储路径、宽度高度、格式、上传人、上传时间。需要注意一点:图片附件在业务上属于“客户询价单”,不属于“报价单”。因为同一份需求包可能生成多个报价单版本,如果附件挂在报价单下,那每次复制报价单时图片文件引用关系都要处理,容易造成冗余或漏拷。把附件挂在需求包下,报价单只通过关联表去引用,逻辑清晰很多。
报价单和图片的关系用一张关联表实现:报价单ID、附件ID、关联类型(主图/参考图/区域标注)、关联明细行ID、备注。这样一张图可以关联到报价单整体,也可以关联到某一条报价明细行,实现“某个零件的价格旁边能看到对应的那张局部图纸”的效果。
4.2 报价版本控制:同一份报价怎么迭代不混乱
版本控制是这套系统的灵魂。我们参考了代码管理器里分支和快照的思路,但做了一定的简化,不引入真正的分支合并,只做顺序版本和差异对比。
每次销售点击“发送给客户”时,系统自动执行一次快照逻辑:生成新版本号,从当前草稿状态复制一份不可变数据,存到正式版本表。正式版本表包含版本号(从1开始递增)、报价单ID、版本数据JSON、创建人、创建时间、发送给客户的时间、客户是否已读状态。后续客户提出修改,销售直接编辑草稿,编辑完成后再次发送,版本号递增,新版本生成,旧版本完整保留。
差异对比功能对销售帮助很大。版本列表页提供“对比”按钮,选择任意两个版本,系统把版本数据JSON反序列化后,逐字段比较,用高亮标注价格变化、数量变化、附件变更。原理不复杂,就是两个JSON递归对比,但业务价值很高,销售跟客户谈价时能直接引用“哪个零件降了多少、为什么”。
4.3 价格联动与税差处理
报价单常用的一个隐藏坑是“总价不等于明细行的累加”。原因多半出在舍入方式和含税不含税切换上。客户要的是含税总价,内部核算要用不含税价,每个明细行乘完税率再四舍五入,累加之后和总价直接乘税率之间会差几分钱。别小看几分钱,客户对账不平会认为你们报价不严谨。
我们做法是:数据库里所有金额字段存储到小数点后4位,展示时保留2位,总价计算以明细行2位舍入后的值累加。同时增加“舍入差异”字段,如果累加值和总价之间存在偏差,系统自动把差异补偿到最后一个明细行,保证“总价=各明细行含税价之和”恒成立。前端展示时用表格展示公式:含税总价 = Σ(各明细行数量 × 单价 × (1 + 税率))。上线后再也没有客户投诉对不上账。
5. 权限、审批与内外协同
5.1 角色权限模型:销售和技术看到的不是同一个报价
报价单涉及的角色比较多,除了内部的销售、技术、商务、财务、管理层,还有外部的客户。不同角色对数据的操作权限天然不同,我采用RBAC + 数据范围两级控制。
RBAC层比较简单,系统定义了六个角色:销售、技术工程师、商务专员、财务、销售总监、超级管理员。每个角色有独立的菜单权限、操作权限和字段权限。例如技术工程师只能看到报价明细的工艺和BOM,看不到成本价和毛利率;销售能看到建议售价和折扣空间,但看不到成本构成;财务能看全部成本数据,但不能修改报价。
数据范围层稍微复杂一点,解决的是“销售A能不能看销售B的报价单”的问题。普通销售只能看到“自己创建或者自己参与协作”的报价单,销售总监能看到本部门全部报价单,超级管理员全量可见。实现上通过一道过滤器,查询时强制拼上数据权限条件,过滤条件判断当前人ID是否在报价单的团队列表里。
这里有个值得分享的经验:权限设计不要一开始就做得特别细,先保证角色之间互相看不到敏感字段,再逐步收口。第一版如果权限太粗,销售可能直接能看到公司底价,后面改起来涉及所有接口,风险极大。
5.2 审批链路:价格管理权限如何下沉
报价审批逻辑看似简单,实践中特别容易出问题。我们设计了多级审批规则,规则可配置,不需要改代码就能调整审批链。
审批规则表长这样的:条件组ID、优先级、匹配条件表达式(比如“金额大于50000 AND 折扣率低于0.85”)、审批流ID。审批流是节点链,节点包括“销售总监审批”“商务经理审批”“总经理审批”,每个节点有审批人、超时时间、审批动作(通过/驳回)。系统在处理“提交审批”动作时,先根据报价金额、折扣、毛利率等指标匹配条件组,决定走哪条审批流,并生成一份待办任务给对应审批人。
因为审批需求是动态变化的,我把“规则引擎”简单化实现,用表达式字符串存规则,不引入重量级规则引擎框架。表达式支持大于、小于、区间、以及或运算,解析器不到200行代码,后续加规则不用发版,运营同学在后台配置就行。
5.3 客户视图与内部视图分离
同一个报价URL,客户打开看到的效果和内部员工打开看到的效果完全不同。我们通过链接入口和token区分身份,客户可以直接打开,用邮箱验证后进入外部视图;员工从系统内部进入,看到完整后台界面。
客户视图刻意做得很轻,包含报价单头、报价总金额、商务条款、核心产品明细(不包含成本)、所有附图原图预览、在线确认按钮和留言框。客户可以在某张图纸下面直接留言“这里公差太大,需要调整”,留言自动通知相关销售。内部视图除了客户看到的内容外,还有成本分析表、毛利预估、审批记录、操作日志、竞争策略建议等内部字段,这些信息通过后端字段级权限控制、统一脱敏后返回前端,不会泄漏到浏览器端里。
这里要提一个我们踩过的坑:第一版把内部字段也返回给前端,只是用CSS隐藏了,后来有客户按F12看了源代码,把成本价直接甩给销售质问。从那以后我规定了所有敏感字段必须在服务端过滤,绝不允许下发到浏览器。做报价系统相关的同行一定要记住这一点,敏感数据必须在服务端裁剪,前端隐藏等于没隐藏。
6. 实操落地:性能、稳定性与问题排查
6.1 大图加载慢:图片预加载和懒加载策略
上线后收到最多的问题之一就是“点开报价单详情页,图片转半天”。排查发现不是网络问题,而是页面一次性加载了全部图片的大图版本,加上客户网络差,页面完全没法看。
我们的优化方案是分级加载加懒加载。列表页只加载256px缩略图,数量控制在50张以内;详情页只加载当前可视区域附近的1024px中图和对应的缩略图,滚动到哪加载到哪。对于图集详情,采用“当前图+前后各1张”的预加载策略,用户连续翻看时基本无感。实测优化后详情页首屏平均加载时间从4.3秒降到了1.1秒,客户反馈明显改善。
6.2 并发编辑冲突:版本号乐观锁与编辑锁
多人同时编辑同一份报价单是常态,技术改了BOM,商务改了价格,销售又在改商务条款。如果没有并发控制,后保存的人直接覆盖先保存的人,要么数据丢失,要么逻辑混乱。我们采用乐观锁方案,报价单表加version字段,每次更新时校验当前版本号和数据库中的版本号是否一致,不一致则拒绝更新并提示重新加载。
后来又加了一层编辑锁。编辑报价单时前端先调用“锁定”接口,在Redis里设置锁记录,有效期30分钟可续期。其他人打开同一报价单时看到“张三正在编辑”的提示条,只能进入只读模式。这个锁是软锁,超时会自动释放,避免人员离开忘记解锁导致其他人一直不能编辑。
6.3 OCR识别率不达预期怎么办
OCR识别率是我们踩坑最多的地方。第一版上线后发现,识别出来的零件图号和材料常有错别字,有些还错得非常离谱,类似“45号钢”被识别成“4S号钢”。根本原因是我们直接用了通用OCR模型,没有针对工程图纸的特点做适配。
后来我们总结了一套完整的优化流程:第一步,识别前做图像预处理,转灰度图、增强对比度、去噪点,虚线、标注线和文字分离开;第二步,针对标题栏做模板定位,裁剪出固定区域再识别,而不是整张图大范围识别;第三步,建领域词库,把常见材料名、图号格式、公差符号、螺纹代号全部收进去,识别结果先做词库匹配,匹配不到再走编辑距离相似度纠正;第四步,人工校正闭环,销售或技术修改过一次识别结果后,系统记录这份信息,后续再次识别同类图纸时优先使用人工校准过的结果。
这几步做完,OCR综合准确率从82%左右提升到94.6%,虽然还做不到完全免校验,但需要人工改的内容已经很少了。做工程类OCR项目的同行,建议直接从“预处理+模板+词库+人工闭环”这套组合拳开始,不要直接裸上通用模型。
6.4 报价单页码混乱和安全问题排查速查表
整理一下实操中常常遇到的问题和排查路径,做成一张表方便大家直接参考。
| 问题现象 | 可能原因 | 排查顺序 |
|---|---|---|
| 报价单页面加载慢 | 图片未分级、未懒加载 | 先看图片请求数量和尺寸,再查后端接口耗时 |
| 客户看到成本价 | 敏感字段前端渲染未过滤 | 检查API响应体是否含成本字段 |
| 并发编辑覆盖 | 缺少版本号或锁机制 | 看数据库更新影响行数、Redis锁记录 |
| PDF导出乱码 | 字体缺失或编码问题 | 检查导出服务字体库、转码规则 |
| 客户没收到报价链接 | 企业邮箱拦截或短链失效 | 检查邮件SPF/DKIM记录、链接过期时间 |
| 图片上传后打不开 | 存储路径权限或后缀转换失败 | 查对象存储访问权限、处理管道日志 |
这套速查表是我们自己团队内部的排障手册,每次线上问题先按这个顺序查,大部分情况都能快速定位。做系统交付后,运维和客服同学有一份这样的表,能省很多低级问题的沟通成本。
7. 上线后的数据反馈与持续迭代
7.1 关键数据指标:怎么衡量系统是不是真的有用
系统上线三个月后,我们统计了五个核心指标,效果供大家参考。
报价制作平均耗时从原先的2.5小时降到45分钟,主要归功于OCR自动填充和BOM模板复用。报价附图的完整性从不到30%提升到94%,因为系统强制要求必须上传附图才能发起审批,未传图根本走不到下一步。报价响应时间(从客户发起到首次报价)从平均16小时降到6小时。客户对报价的在线确认率从零提升到约35%,虽然大头还是线下签订,但线上回执对销售跟进节奏很有参考价值。因为版本混乱导致的报价事故,从每月2到3次降为零。
这些指标不算惊艳,但对于事务型的报价协同系统来说,已经能明显感受到工作方式的改变。最开心的是两个销售主动说“现在新来的实习生只要会传图就能把基础报价搭建起来,不用再问老师傅了”。
7.2 上线初期暴露出最尴尬的问题
系统上线第一周,我们收到了内部最集中的吐槽:销售觉得“上传图片太麻烦”,要求恢复微信传图、Excel报价的方式。当时压力挺大,差点就把强制上传的限制放宽了。后来仔细分析用户日志,发现不是销售不想传图,而是他们手里积压了十几张历史图片和Excel表,一次性搬家成本高。
解决方式是用两周做了批量导入工具,支持文件夹批量上传、Excel批量导入、旧邮件附件批量归档,同时允许销售先建草稿后补图。过渡期结束后检查了数据,发现97%的新报价都满足流程要求,手动放宽的情况极少。这次经验让我明白,流程改革最难的往往不在系统本身,而在变更管理。如果评估过用户迁移成本高,一定要提前安排数据搬家工具和宽限期。
7.3 后续迭代方向
系统已经平稳运行,后续迭代主要围绕三个方向。第一是移动端轻量化,销售外出见客户、现场勘验场地时,需要拿手机拍完照片就能发起报价,拍完自动上传、自动标注水印,减少回办公室补传的环节。第二是智能报价建议,基于历史成交价和材料市场价波动,在商务核价时自动推荐区间价,辅助决策,而不是完全凭经验拍脑袋。第三是客户自助报价门户,让老客户自己上传图纸、自己选配置,系统自动跑出一个预估报价,销售只需人工复核,以此降低前期沟通成本。
这套系统的设计思路并不复杂,核心就是把“报价要有依据”这件事做到极致。无论是流程图、数据模型还是权限控制,每一条设计背后都有实际踩坑的经验在支撑。如果你正在做类似的系统,希望这篇内容能帮你绕开我们走过的弯路,把报表周期从三天缩到半天。最后再分享一个个人体会:做业务系统,真正的难点从来不是技术实现,而是对业务场景的深度理解。多花时间跟销售、技术、商务聊,比多调研十个框架都管用。
