Skip to content

VOL Pro 开发 ERP:成本重估、开发流程清单、优化建议 ​

第二版。相比第一版(VOL_Pro_ERP_能力评估.md,那份是"框架能力是否具备"的证据清单),本文回答三个问题:要花多少、按什么顺序做、怎么做才不返工。 估算前提:1 名熟悉 Vue3 + .NET 的中高级全栈;1 人日 = 8 有效工时;已掌握框架基本用法(上手期 1–2 周另计)。


一、成本重估 ​

1.1 一句话结论 ​

框架能替你干掉约 60% 的工作量,但被干掉的 60% 恰恰是"不值钱"的那部分 CRUD。ERP 真正的成本——库存事务、成本核算、单据流转、往来核销——框架帮不上忙,而且这部分的比重比大多数人预估的高。

1.2 三种场景的估算 ​

场景单据数工作量折合说明
A. 进销存 + 往来(采购/销售/库存/应收应付,无生产、无总账)12–1570–100 人日1 人 × 4–5 月最现实的起步范围,建议先做这个
B. 完整 ERP(A + 生产制造 + 总账凭证 + 成本核算)25–30150–220 人日1 人 × 8–10 月,或 2 人 × 4–5 月生产与成本部分占增量的一半
C. 行业定制版(B + 行业特性,如批次效期、序列号、委外、多单位换算)35+250–350 人日3 人 × 4–5 月不建议一开始就做

对比:纯自研(自建框架 + 业务)约 300–450 人日,即 VOL Pro 节省 55%–65%。

1.3 分模块人日明细(场景 A,共约 92–96 人日;2026-10-31 修订:补交付与运维基设) ​

模块人日框架省了多少主要成本在哪
环境/规范/脚手架3—命名规范、Git 策略、字段标准
基础资料(物料/分类/仓库/库位/供应商/客户/单位/税率)8省 70%几乎是纯 CRUD,生成器出完微调即可
公共基类抽取(单据基类 + 库存服务 + 单据关系表)8省 0%必须先做,否则后面全线返工
采购链路(请购/订单/入库/退货/发票)18省 50%上下游选单、数量反写、订单关闭判定
销售链路(报价/订单/出库/退货/发票)18省 50%同上 + 价格策略、信用额度
库存(调拨/盘点/报损报溢/批次/预警)15省 40%库存事务一致性 + 移动加权成本,最硬的一块
往来(应收应付/收付款/核销/对账)12省 40%核销规则、账期、账龄
审批流挂接4省 80%FormWorkFlow 配流程 + 挂节点
打印模板6省 50%每套单据一个模板,套打调位置很耗时
OSS 文件存储(自建)3省 0%框架没有,必须写
消息/邮件/定时任务集成3省 80%现成,接一下
权限/菜单/数据权限3省 70%配置为主
交付(期初/报表/培训)5–8省 30%期初库存成本初始化、对账单报表、用户手册(阶段 10)
运维基设(备份/环境分离/部署)2–3省 0%四.P0 新增四项
测试 + 对账 + 上线10—库存对账、数据校验、UAT

1.4 一个必须知道的"成本陷阱" ​

框架生成的单表页面看起来 30 分钟就能出一个功能,这会严重误导排期。真实耗时结构是:

生成器出骨架        0.5 小时   ← 你看到的"快"
前端页面调整        3-4 小时   ← 列、查询条件、合计、导入导出、校验
后端业务逻辑        8-16 小时  ← 单据编号、状态机、上下游、库存事务、校验规则 ★真正的大头
打印模板            3-4 小时
联调与修 bug        4 小时
────────────────────────────
单个复杂单据        2.5-3.5 人日

排期时按"单据的复杂度"而不是"单据的数量"估:简单档案类(物料、仓库)0.5 人日/个;带明细的单据 2.5–3.5 人日/个;带上下游流转的单据 4–5 人日/个。


二、可行性判定(修正第一版) ​

项第一版修正后依据
主从表保存✅✅ 无异议官方文档 /docs/cs/service/add:AddOnExecuting(order, list),base.Add 内部事务,返回 Error 即回滚
合计✅✅ 双通道确认前端 x.summary + 后端 SummaryExpress / GetDetailSummary<Detail>
单元格合并✅✅:spanMethod 官方写法明确
导入导出✅✅Export 有 Limit、ExportColumns、ExcelHeaderMap、ExportCustomValue
审核流✅✅AuditWorkFlowExecuting/Executed,lastAudit + RewriteFlow 回退
打印🟡🟡→✅(降级风险)官方有 /docs/print/ 4 篇文档,比第一版判断乐观;仍保留"批量/套打需客户端"的提示
大数据量表格未评✅官方 /docs/web/general/tableV2 专门讲表格卡顿与大批量编辑
OSS🔴🔴 维持官方 upload 文档只有 UploadFolder 本地路径,无任何云存储章节,二次确认

结论:技术上完全可行,没有阻塞项。 真正的风险不在"能不能做",在下面第四节。


三、开发流程清单 ​

阶段 0:地基(3 人日)— 不要跳过 ​

#动作产出坑
0.1定数据库命名规范:表名 Erp_XXX、主表主键统一、明细表外键 {主表}Id、统一 CreateID/Creator/CreateDate/ModifyID/Modifier/ModifyDate《命名规范》文档生成器靠规范批量产出,规范乱了后面每个页面都要手改
0.2定字段标准:金额 decimal(18,4)、数量 decimal(18,6)、单价 decimal(18,6)、日期统一 datetime规范文档精度中途改 = 全库返工
0.3定单据通用字段:BillNo / BillDate / Status / AuditStatus / AuditId / Auditor / AuditDate / Remark / TotalAmount / TaxAmount规范文档所有单据统一,公共基类才能抽
0.4决策:要不要多租户(TenancyId)、要不要数据权限(UserAuth)、要不要乐观锁(DataVersionField)决策记录这三个后期加是灾难级返工,必须现在定
0.5Git 策略:生成文件 vs 手写文件分开看 diff;规定只改 extension/**/*.jsx 和 Services/**/Partial/CONTRIBUTING见 4.5

阶段 1:数据建模(5 人日) ​

  • 用 src/views/builder/database/TableEditorWorkspace.vue 或直接在数据库建表(推荐后者 + syncTable 同步)
  • 每一张明细表必须有:主键、主表外键、SortNo(行号)、CreateDate
  • 建"单据关系表" Erp_BillRelation(见 4.3),这是全局最重要的一张表
  • 建库存表 Erp_Inventory(物料+仓库+批次 唯一键)、库存流水表 Erp_InventoryFlow

阶段 2:代码生成(0.5 人日/单) ​

用 src/views/builder/coderV3.vue:

  1. LoadTable 载入表 → 配置主表字段(编辑类型、查询行、必填、字典)
  2. 配置明细表(勾选一对多)
  3. CreateModel 生成实体 → CreateServices 生成服务层 → CreateVuePage 生成 Vue 页面 → CreateMenuVue 生成菜单
  4. 前端路由必须手动加到 src/router/viewGird.js(框架不会自动加,菜单是后端下发的)

检查点:生成的页面能跑通增删改查 + 导入导出,再进入下一阶段。这一步没跑通别往下走。

阶段 3:页面配置(每个单据 3–4 小时) ​

按顺序做,别跳:

  1. columns 列配置:宽度、对齐、formatter(/docs/web/table/formatter)、隐藏列
  2. 查询条件:生成器勾"查询行" + gridRef.queryFields=[...](/docs/web/table/queryFields)
  3. 默认排序(/docs/web/table/sort)
  4. 合计:x.summary=true + 后端 SummaryExpress(/docs/web/table/summary)
  5. 明细表:列、合计(GetDetailSummary)、实时计算(/docs/web/table/detailCalc)
  6. 导出:ExportColumns + ExcelHeaderMap

阶段 4:业务逻辑(大头,8–16 小时/单) ​

全部写在 VolPro.ERP/Services/erp/Partial/{表}Service.cs,前端写在 src/extension/erp/erp/{表}.jsx。

每个单据的固定动作:

  1. 重写 Add/Update,用 AddOnExecuting(order, list) 做校验 + 默认值
  2. 单据编号:mainEntity.CreateCode()(/docs/cs/dev/code 有自增流水号)
  3. 状态机:草稿→待提交→审核中→已审核→已关闭/作废(用统一枚举,别各写各的)
  4. 上下游:选单加载 + 保存时反写上游数量 + 判定上游是否关单
  5. 库存:调用统一的库存服务(见 4.2),绝不自己写 SQL 改库存
  6. 前端校验与联动写在 jsx 的 methods(onInit/onInited/modelOpenAfter)

阶段 5:审批流挂接(0.5 人日/单) ​

  1. 在 src/views/sys/formflow/ 配流程(节点、审批人、条件分支)
  2. SaveModel.IsFlow = true
  3. 重写 Audit,用 AuditWorkFlowExecuting/Executed;lastAudit=true 时才执行"生效"逻辑(如库存过账)
  4. 反审用 base.RewriteFlow(order)(/docs/cs/service/antiAudit)

关键设计决策:库存是在"保存时"扣减,还是"审核通过时"扣减? 必须在阶段 4 之前定死。推荐:草稿不扣,审核通过才扣(否则作废单会污染库存)。

阶段 6:打印(0.5–1 人日/单) ​

  1. src/views/print/print.vue 设计模板(/docs/print/config)
  2. printBefore 钩子传参(/docs/view-grid/methods/printParams)
  3. 抽象一层 IPrintService,方便后续从 hiprint 换成服务端 PDF

阶段 7:集成(6 人日) ​

项动作
OSS(自建,3d)定义 IFileStorage → 本地实现 + OSS/MinIO 实现 → 配置切换 → 前端 VolUpload.vue 的 uploadOSS() 填实(STS 临时凭证直传)
消息推送SignalR 已就绪,接 /hub/message,写待办表
邮件MailHelper + MailBackgroundService 队列,配 appsettings.json 的 Mail
定时任务Quartz:库存预警、账龄计算、单据超时关闭;多实例部署要改持久化 JobStore

阶段 8:权限与菜单(3 人日) ​

菜单 → 角色 → 按钮权限(authBtn)→ 字段权限(saveAuthFields)→ 数据权限(UserAuth)

阶段 9:测试与上线(10 人日) ​

  • 库存对账报表必须做:理论库存 vs 流水累计,每天跑一次,对不上就报警
  • 重点回归:并发保存同一单据、审核中途驳回、上游单据被删除、导入脏数据
  • 大数据量压测:单表 10 万行、单单据 500 明细行的页面响应

阶段 10:交付与期初(5–8 人日,2026-10-31 补排) ​

项动作量
期初数据期初库存导入(含成本初始化,走 4.11 SqlBulkInsert + InventoryService 期初专用接口,不留后门直接 INSERT)、期初应收应付、客户/物料档案迁移。必须客户盘点配合,预留 2 轮校验时间3–5 人日
报表平台进销存汇总表、往来对账单是交付必爆需求。用框架静态页面生成器做通用查询报表,导出 Excel 兜底按张估 0.5–1 人日,预留 3–5
用户手册/培训按角色写操作手册(打印/导入导出/审核流是提问重灾区),至少 1 场现场培训1 人日

四、优化建议(按价值排序) ​

★★★★★ 1. 先抽公共基类,别急着写第一个单据 ​

这是最大的一个坑。 25 个单据都有单号、状态、审核、明细校验、创建人,如果各写各的,后期改一处要动 25 个文件。

建议先花 8 人日建三个公共件:

  • ErpBillService<TMaster, TDetail> 基类:统一单号生成、状态流转、审核前后钩子、明细通用校验、金额合计回写主表
  • InventoryService:库存唯一入口(见第 2 条)
  • BillRelationService:上下游关系(见第 3 条)

之后每个单据只写"自己特有的规则"。这 8 人日会在第 5 个单据时开始回本。

★★★★★ 2. 库存操作收敛到唯一入口 ​

所有影响库存的动作(采购入库、销售出库、调拨、盘点、报损、退货)只能调用同一个 InventoryService.UpdateStock(...),内部完成:写库存流水 → 更新库存余额 → 计算移动加权成本 → 校验负库存。

严禁任何单据 Service 自己写 SQL 改库存表。 库存对不上是 ERP 项目最常见的死因,而且一旦发生,排查成本极高。

★★★★★ 3. 建一张通用"单据关系表",别为每对上下游写一套 ​

Erp_BillRelation:
  SourceType, SourceId, SourceRowId   -- 上游单据类型/主键/行
  TargetType, TargetId, TargetRowId   -- 下游
  Qty, ReferencedQty                   -- 上游数量、已引用数量

有了它,"选单加载"和"反写关单"能写成通用逻辑:新单据 A→B 只需配置一行关系,不用写代码。 否则采购订单→入库、销售订单→出库、入库→发票……每对写一遍,10 对就是 10 套几乎一样的代码。

★★★★☆ 4. 金额精度与税率规则,第一天就定死 ​

decimal(18,4) 还是 (18,2)?含税单价还是不含税?税额按单头算还是按行算再汇总(两者会差几分钱)?尾差怎么摊?

这类问题后期改 = 全库 + 全部打印模板 + 全部报表返工。 现在花 2 小时定清楚,写进规范文档。

★★★★☆ 5. 严守"生成区 / 手写区"纪律 ​

只能改这两个地方:

  • 前端 src/extension/**/*.jsx(由 views/**/*.vue 顶部 import extend 引入)
  • 后端 Services/**/Partial/ 和 Controllers/**/Partial/

其他任何生成文件都不要手改。 一旦重新生成(比如加了字段),你的改动会无声消失。建议在生成前先 git status 确认干净,生成后立即 diff 检查。

★★★★☆ 6. 不要用框架自带的 ERP 模块当基础 ​

VolPro.ERP 的 42 个实体是演示级:库存计价、成本结转、核销、账期都没做完整。"照着改"比"重新建"更慢,因为你要先花时间分辨哪些是演示假逻辑。

建议:删掉 ERP/MES/dbtest 三个示例模块(router/viewGird.js 注释里官方明说可以删),按自己的建模来。但保留它们作为参考(尤其 ERP_InventoryIo/ 的选单交互范式值得看)。

★★★★☆ 7. 打印和文件存储都要做抽象层 ​

  • IPrintService:现在用 hiprint,将来可能要服务端 PDF(批量打印/套打需求)
  • IFileStorage:现在本地,将来 OSS/MinIO

两个接口各 1 小时,能避免将来各改 20 个调用点。

★★★☆☆ 8. 明细行多的时候,提前用 tableV2 ​

官方 /docs/web/general/tableV2 专门处理表格卡顿。ERP 单据明细动辄几百行,等卡了再换就晚了——在第一个复杂单据上直接用 V2。

★★★☆☆ 9. 前端列配置抽到 options.js ​

参考 src/views/erp/erp/ERP_SaleOutOrder/options.js 的做法。同一个物料选择器在 10 个单据里出现,改一次就全生效。

★★★☆☆ 10. 审批流选 FormWorkFlow,不要选 WorkFlow ​

框架有两套:WorkFlow/(图状流程)和 FormWorkFlow/(表单审批流)。ERP 单据审批用后者,前者是为复杂流程图设计的,用在单据上会过度复杂。

★★★☆☆ 11. 批量操作用 SqlBulkInsert ​

导入、期初数据、库存初始化,用 /docs/cs/dev/sqlBulkInsert 的批量插入,别一行一行插。

★★★☆☆ 12. 缓存字典,别每个下拉框都查库 ​

物料分类、单位、仓库这类低频变化的数据,用 /docs/cs/dev/cache 缓存,前端 initDicKeys 刷新。ERP 页面下拉框极多,不缓存会明显卡。

★★☆☆☆ 13. 提前规划多组织架构 ​

如果客户有多个公司/工厂,TenancyId + UseDynamicShareDB 必须阶段 0 就定。后期加租户字段要改每一张表和每一个查询。

★★☆☆☆ 14. 做库存对账工具和日志,别等出问题 ​

  • 每天定时跑:库存余额 vs 流水累计,差异报警
  • 关键操作(库存变动、审核、反审、删除)写审计日志(VolPro.Core/Middleware/ActionLog.cs 已有)

框架级优化清单(2026-10-31 补充,按投入产出分层) ​

与上面 14 条互补:4.1–4.14 是业务开发建议,这一节是框架本身的改造与补齐。基类三件套见 4.1–4.3,此处不重复。

P0:立项即做(缺了必返工/阻塞上线)

项现状(源码证据)怎么做量
OSS 文件存储VolUpload.vue 的 uploadOSS() 空函数;后端 Upload() 只写本地磁盘换 MinIO:后端 STS 凭证接口 + 填实前端上传 + $global.oss.url 配 CDN1–2 人日
Quartz 持久化内存调度器无 JobStore,多实例部署重复执行补 ADO.NET JobStore(QuartzNETExtension 接入点现成);或任务机单实例2–3 人日
公共基类三件套见 4.1–4.3同前8 人日
数据库备份与容灾远程 SQL Server 在云服务器上,全文无备份策略;ERP 数据丢失 = 致命每日全备 + 日志备份 + 恢复演练一次;云厂商快照兜底0.5 人日
环境分离dev 直连远程库,误操作即生产事故至少 dev/prod 两库;DDL 存档已有(erp_slice_01_ddl.sql),建议引入 DbUp 之类工具管 migration1–2 人日
密钥管理appsettings.json 的 SQL 密码明文在仓库里移出 Git(环境变量/user-secrets),并先改掉已泄露的密码0.5 人日
部署方案无 Nginx/HTTPS/日志轮转规划反代 + HTTPS + 前端产物部署 + SeriLog 滚动轮转(现在 log 无限增长)2–3 人日

P1:防坑改造(第一周做完,省后面的调试命)

  1. 菜单缓存刷新口子:Sys_MenuService 的 static _menus 只能靠"界面保存菜单"或重启刷新(已实际踩坑:改库改 Sys_Menu.Auth 重新登录无效)。加一个 [ApiActionPermission(ActionPermissionOptions.SuperAdmin)] POST api/menu/refreshCache,内部清 _menus + 刷 inernalMenu 版本号。30 分钟工作量,终结一类排查灾难。
  2. 请求 DTO 规范:建 VolPro.Entity/Dto/ 统一放请求 DTO(全显式 [JsonPropertyName("camelCase")],否则可能静默绑成 null);在 ApiBehaviorOptions 把 415/400 转成带字段名的错误信息(现在响应体为空,前端只见"服务器处理异常")。官方示例 voidBill 的 [FromBody] Guid 裸标量写法别照抄。
  3. 可空状态列防御:可空列存 NULL 时 SQL 层 x.Status != 4 求值 UNKNOWN 整行被过滤(已实际踩坑)。ERP 单据状态列 DDL 统一 NOT NULL DEFAULT 0,从源头消灭三值逻辑。
  4. 前端模式沉淀 composables:实战手写过的三个模式抽到 src/composables/ 复用——useSelectionPool(勾选池 Map + switching 标志挡空 selection-change + toggleRowSelection 恢复)、useOptionsPatch(adjustMainOptions 运行时改生成配置)、useGridBridge(parentCall 跨渲染链桥接)。

P2:质量与运维(数据跑起来之后)

  • 库存服务单元测试:框架自身无单测,别跟着裸奔。InventoryService 收敛后(4.2)天然可测,重点覆盖并发扣减、负库存拦截、反审冲销。
  • 缓存/SignalR Redis 化:UseRedis 开关现成(CacheContext),多实例部署前打开;SignalR 补 Redis backplane,否则消息只达单机。
  • 打印服务端 PDF 通道:hiprint 静默/连续打印依赖本地 socket 客户端,客户现场难部署。加服务端渲染 PDF(配合 4.7 的 IPrintService 抽象),批量打单刚需,3–5 人日。
  • Swagger 分组 + 权限标注:接口按模块分组,[ApiActionPermission] 反映到 swagger 描述,联调排查契约问题(415/字段名)快得多。
  • 浏览器兼容范围确认:客户现场若有老 Chrome/360 兼容模式,vite 默认产物跑不了,需加 @vitejs/plugin-legacy;提前跟客户确认目标浏览器,别等装机当天发现。

不建议做的

  • 别重构框架内核(ViewGrid/ServiceBase):收益低、破坏生成器兼容,一切通过 Partial/extension 外挂。
  • 别拿 VolPro.ERP 示例当产品:同 4.6。
  • 别用界面上"直接改库"的方式调权限:改 Sys_Menu/Sys_RoleAuth 后必须走菜单保存或重启,否则后端静态缓存持续吐旧数据(见 P1 第 1 条,做完刷新口子后此风险消除)。

五、风险清单 ​

风险概率影响应对
库存与流水对不上高致命唯一入口 + 每日对账 + 事务
重新生成代码覆盖手写逻辑中高严守 4.5 纪律 + 生成后 diff
单据明细量大导致页面卡顿中中一开始就用 tableV2
精度/税率规则中途变更中高阶段 0 定死
Quartz 多实例重复执行中中上生产前改持久化 JobStore 或单实例跑任务
打印套打需求超出 hiprint 能力中中抽象 IPrintService,留换方案余地
上下游反写逻辑散落各处高高通用单据关系表(4.3)
前端主子表交互定制超出生成器中中复杂单据预留 2 倍时间
数据库无备份高致命四.P0:每日全备 + 日志备份 + 恢复演练
密钥明文入库(SQL 密码在 Git 仓库)高高四.P0:移出仓库 + 立即改密

六、最小启动建议 ​

如果只想先验证可行性,两周做一个垂直切片:

物料档案 → 采购订单(含明细)→ 采购入库(引用订单、反写、扣库存)→ 审批流 → 打印 → 库存查询带合计

这一个切片会同时验证:主从保存、上下游、库存事务、审批、打印、合计、导入导出——框架 80% 的关键能力。做完它,整体排期的误差能从 ±50% 收敛到 ±20%。不要一上来就铺开做 30 个单据。