QUOTE
把零散经验「归」集一体、深「藏」于库,需要时随时调用、再生新策。
—— 李仁龙
本项目面向系统集成行业的售前技术工程师,提供可沉淀个人经验的协同工具集,主打快速报价与配置单管理。
《归藏》取自上古三易之一(与《连山》《周易》并列),以「坤」卦为首——坤为地,象征收藏、承载、化育万物。
关于这个项目
首先,感谢当下 AI 行业的快速发展——让我这种「只懂一丢丢代码」的人,也能通过自然语言完成Vibe Coding。这是一个完全由我与 AI 联合开发的纯 AI 构建产物。后续我很期待能跟其他售前兄弟一起协同完善这个项目。
其次,做这个项目的初衷:我作为售前工程师,经常要面对常规计算和紧急的项目报价。我希望这个工具只是个开始——不远的将来,我能用它跟客户吹着 NB,让 AI 同步报底价。
本篇是归藏 · 售前管理工具集 v0.1.3 → v0.1.7 的迭代总结。这次属于「持续打磨业务体验」阶段——不再像 v0.1.2 那样做大刀阔斧的架构改造(SQLite→PG、bind mount),而是聚焦在让日常用起来更顺手。
5 个新功能 patch + 1 个紧急修复 + 1 次开源版发版,全在本地生产环境跑通后同步到了 Gitee 开源仓库。
本文看点
01
四大核心模块
02
7 项变更详情
03
踩坑与发版
01
FEATURES
项目特点
四大核心模块
一、售前估算工具集
覆盖ICT系统、信息安全、音视频系统、楼宇自控系统等场景的常用估算工具,几分钟就能出报价初稿。
二、设备库
沉淀日常产品报价数据。v0.1.7 加入了列表分页 + 检索结果分页 + 加入报价单去弹窗 + 价格类型自动估算,报价单模块可一键匹配设备、快速生成清单。
三、报价单
服务项目报价流程:先通过各类技术模块生成清单,再匹配设备库的设备,形成「清单 ↔ 设备」联动。v0.1.4 新增筛选栏(项目下拉 + 关键词搜索 + 300ms 防抖),报价单列表浏览效率提升 3 倍。
四、方案包
为售前工程师的私有报价模板而生。既能匹配现有设备,也支持自定义项目清单——把经验做成可复用的「乐高积木」。
02
CHANGELOG
变更总结
48 小时 · 7 项变更
7
项变更
1
新接口
2
处分页
1
次发版
这次属于「持续打磨业务体验」阶段——不再像 v0.1.2 那样做大刀阔斧的架构改造(SQLite→PG、bind mount),而是聚焦在让日常用起来更顺手。
v0.1.3 · 建筑默认值修复
编辑项目建筑信息时如果忘了填层高/长/宽,保存会失败或保存出空白值;后续做安防监控估算时因为尺寸缺失直接阻断计算。
修法:建筑信息留空 → 自动用 20 / 20 / 5 兜底;安防估算缺尺寸 → 也不再阻断,改用默认值继续算。新增 _fillDefault / _fill / _parseVal 三个 helper 函数统一处理。
v0.1.4 · 项目报价单筛选增强
报价单列表只能按项目筛选,遇到具体业务想找某条报价得翻半天。
修法:后端新增 GET /api/quotes 接口,支持 project_id + keyword 两个参数并行使用;前端加筛选栏(项目下拉 + 关键词输入 + 重置),关键词 300ms 防抖避免每打一字请求一次;表格新增「项目」列;时间显示 fix 兼容 RFC 2822 / ISO 8601 / 时间戳三种格式。
老接口 GET /api/projects/<id>/quotes 保留不删,调用方不用改。
v0.1.5 · 设备库「加入报价单」去弹窗
在设备库点「加入报价单」时,每次都弹窗让用户选项目。一天加 20 个设备要点 20 次,体验很烦。
修法:优先读 localStorage.currentProjectId(跟 Quotation.vue 共享状态);有项目 → 直接加入不弹窗;没项目 → warning 提示并自动跳转到报价单页。
v0.1.6 · 价格类型智能转换
设备库 15 台设备全部只有成本价(type=cost),没有市场价。往报价单加设备时要么手动算要么报错。
修法(自动判断逻辑):
· type=market → 直接用
· type=cost + 设备有市场价记录 → 用市场价
· type=cost + 设备没有市场价 → 成本价 × 1.6 估算(保留 2 位小数)
估算时审计信息自动写进 remarks 字段:[原始成本价: ¥19000, 估算系数 1.6],既保留可追溯性又不影响老数据。
v0.1.7 patch1 · 设备库列表分页
设备库默认视图一次性渲染所有设备卡片,15 台就开始慢了;以后设备多了更难受。
修法:底部加 el-pagination 分页控件,8 条/页;搜索/筛选条件变化时自动重置回第 1 页。选前端分页而不是后端分页,原因是现有筛选逻辑是基于前端 computed 链实现的,切后端会破坏整套筛选。
v0.1.7 TDZ 紧急修复 · minify 后报 Io 错
v0.1.7 patch1 发布后浏览器控制台报:
can't access lexical declaration 'Io' before initialization
根因:DeviceLibrary.vue 里的 listFilteredDevices / filteredBundles 这两个 computed 函数体里直接引用了 quickFilterSystem.value,但这两个 const 在文件后面才声明。Vite 生产构建会做 hoist + minify,把变量名压成单字母后触发 JS 的 TDZ 规则,页面直接打不开。
修法:把 quickFilterSystem / quickFilterCategory / quickAvailableCategories 三个 const 声明前移到 L2288 之前,watch 监听位置不动。以后 <script setup> 里新增 const 引用,必须前移声明到所有引用方之前。
v0.1.7 patch2 · 设备检索结果分页
patch1 只给「默认列表视图」加了分页,但「设备检索」视图(按关键词/系统/分类/品牌等多条件筛选)走全量渲染,没分页。
修法跟 patch1 同一套模式:检索结果底部加 el-pagination,8 条/页;搜索/筛选条件变化时自动重置第 1 页。新增 SEARCH_PAGE_SIZE / searchCurrentPage / pagedSearchDevices 三个常量。
v0.1.7 开源版发版 · 同步 Gitee
5 个新功能 patch + TDZ 修复 + 文档整理,累计 10 个文件改动,同步到开源仓库。
Gitee 仓库:gitee.com/lirenlong/pre-sales-management-toolkit
03
PITFALLS & RELEASE
踩坑与发版
踩坑总结(防止下次再踩)
Vite TDZ 暴露
computed/函数体里引用了后声明的 const → Vite hoist + minify 压成单字母 → 触发 JS TDZ 规则。修法:前移被引用的 const 声明,不是后移引用方。
docker build 假成功
不带 --no-cache 时 BUILD CACHE 命中会跳过 COPY . . + npm run build → dist 不更新。始终用 docker build --no-cache,并用 docker exec 看容器内 dist 验证。
pip 走 pypi.org 超时
Dockerfile 写 RUN pip install --upgrade pip 默认走 pypi.org 会 ReadTimeoutError。改走阿里云镜像,跟 requirements.txt 保持一致。
多环境 nginx.conf 容器名
生产版 nginx.conf(容器名 presales-backend)被错误同步到 build 版(应该是 presales-build-backend)。同步脚本要把 frontend/nginx.conf 加到 BUILD_UNIQUE 永远不覆盖。
datetime RFC 2822 序列化
PG RealDictRow 用 dict(r) 序列化时 datetime 被 str() 化为 RFC 2822 格式,前端 new Date() 解析出 NaN。重写 formatLocalTime 让 JS 原生支持多种格式。
v0.1.7 Gitee 公开版 · 安全审计
发版前做了完整安全审计,结果如下:
结论:开源版可以安全公开。反推生产数据 100% 不可能;其他用户 clone 后能成功部署,但建议立即修改默认账号密码。
∞
EPILOGUE
归藏不露锋 · 售前不求忙
愿这套工具能让你:
少加 1 小时班
少在 1 个 Excel 里死磕
多 1 个按时下班的傍晚
—— 李仁龙 · 2026.08.16
我是 李仁龙 ,可能是个搞技术的/Vibe Coding 实践者/会飞/会喷火/龙系数码宝贝/被光选中的人。
微信号:lrlanael
如果你觉得今天这篇有收获,欢迎点赞、在看、转发三连,我们下篇见。
夜雨聆风