外观
VOL Pro 3.5.8 用于完整 ERP 系统的能力评估
评估方式:源码实证(每项均给出文件路径与关键代码),非文档推断。 环境已跑通:前端 http://localhost:9000(200)、后端 http://localhost:9100(200)、远程 SQL Server 101.132.125.215:58900 TCP 可达。 说明:本报告未做浏览器端登录与交互验证,页面级行为需你登录后确认。
一、结论速览
| # | 能力项 | 评级 | 一句话结论 |
|---|---|---|---|
| 1 | 主从表一起保存 | ✅ 开箱 | SaveModel 主+明细+删除键一次提交,后端单事务写入 |
| 2 | 表格筛选 | ✅ 开箱 | 搜索区 + 列筛选 + 快捷查询 |
| 3 | 排序 | ✅ 开箱 | Sort/Order 后端排序 |
| 4 | 合计/汇总 | ✅ 开箱 | 前端汇总行 + 后端 Summary 字典双通道 |
| 5 | 单元格合并 | ✅ 开箱 | spanMethod 属性直接传函数 |
| 6 | 导入 | ✅ 开箱 | 模板下载 → 校验 → 事务内写入,支持明细表导入 |
| 7 | 导出 | ✅ 开箱 | 可按当前界面列导出 |
| 8 | 打印 | 🟡 需定制 | hiprint 模板设计器齐全,但套打/批量需配客户端 |
| 9 | 审核流 | ✅ 开箱 | 两套流程引擎(图状工作流 + 表单审批流) |
| 10 | 自定义列格式 | ✅ 开箱 | 格式化/自定义渲染/字典/日期金额格式化 |
| 11 | 自定义查询条件 | ✅ 开箱 | 用户自选字段+操作符,后端支持 or/多字段/分组 |
| 12 | 上下游关联加载 | 🟡 需开发 | ERP 示例有完整范式可抄,但必须按业务重写 |
| 13 | 文件存储 OSS | 🔴 未实现 | ali-oss 依赖被注释,上传走本地磁盘,需自建 |
| 14 | 消息推送 | ✅ 开箱 | SignalR 双 Hub(站内消息 + 性能监控) |
| 15 | 审核流推送 | ✅ 开箱 | 流程节点通知 + 站内待办 |
| 16 | 邮箱推送 | ✅ 开箱 | MailHelper + 后台队列异步发送 |
| 17 | 定时任务 | ✅ 开箱 | Quartz 完整,界面增删改启停 + 执行日志 |
总体判断:可以作为 ERP 底座,17 项中 12 项开箱即用、3 项需定制、1 项(OSS)需自建、1 项(上下游)是业务开发而非框架能力。 真正的成本不在"框架能不能做",而在 ERP 业务建模与库存/成本核算逻辑——那部分框架的 ERP 示例只是演示级,必须重写。
二、逐项证据
1. 主从表一起保存 ✅
前端提交结构 SaveModel(api_sqlsugar/VolPro.Entity/DomainModels/Core/SaveDataModel.cs:7):
csharp
public class SaveModel {
public Dictionary<string, object> MainData; // 主表
public List<Dictionary<string, object>> DetailData; // 明细
public List<object> DelKeys; // 要删的明细主键
public List<DetailInfo> Details; // 一对多明细(多张子表)
public bool IsFlow; // 是否走审批
public string DataVersionField, DataVersionValue; // 并发版本号
}后端 ServiceBase.AddAsync(VolPro.Core/BaseProvider/ServiceBase.cs:182,206)——单事务内插入主表+导航明细:
csharp
mainEntity.CreateCode(); // 自动生成单据编码
baseWebResponse = await repository.DbContextBeginTransactionAsync(async () => {
await repository.BaseDbContext.InsertNavDetailAsync(mainEntity);
var extendRes = MultipleTableEntity.PersistExtendFields(mainEntity);UpdateAsync(:320,396)同样是事务内 DbContextBeginTransaction(SaveData),删改新增一次完成。
前端侧:src/components/basic/ViewGrid/ViewGridDetails.vue、ViewGridDetailFooter.vue(明细合计)、ViewGridProviderDetail.jsx。三级明细后端也有支持(PageDataOptions.DetailTable)。
落地要点:框架只保证「主表 + 挂在主表上的明细」在一个事务。跨单据的副作用(写库存、写应收)必须在
Services/erp/Partial/XXXService.cs里自己加进同一事务,示例见VolPro.ERP/Services/erp/Stock/ErpPurchaseInboundHelper.cs。
2–5. 筛选 / 排序 / 合计 / 单元格合并 ✅
后端查询契约 PageDataOptions(VolPro.Entity/DomainModels/Core/LoadSingleDataModel.cs:5):
csharp
public string Sort { get; set; } // 排序字段
public string Order { get; set; } // asc/desc
public List<SearchParameters> Filter; // 自定义查询条件
public string[] Columns; // 导出列与界面显示一致
public Dictionary<string, string> Summary; // 后端汇总值(合计)其中 SearchParameters 支持 DisplayType(控件类型)、Fields(一个条件命中多字段)、Or、Group——足以支撑 ERP 里"按日期区间+多仓库或条件"这类查询。
前端对应模块(src/components/basic/VolTable/):
VolTableSummary.js—— 合计/小计VolTableFormat.js—— 列格式化VolTableRender.js/VolTable-V2-Render.jsx—— 自定义渲染(jsx 写单元格)VolTableDicData.js、VolTableFile.js、VolTableEdit.js、VolTableLoadData.js
单元格合并有原生属性(VolTable/VolTableProps.js:180):
js
spanMethod: { type: Function, default: ({row,column,rowIndex,columnIndex}, rows) => {} }VolTable.vue:93 绑定 :span-method="cellSpanMethod",:1362 处把整表数据 rows 回传给你算合并坐标。用法示例见 src/views/table/tableSearch.vue:79。
6–7. 导入 / 导出 ✅
ServiceBase 内置四个虚方法(VolPro.Core/BaseProvider/ServiceBase.cs):
| 方法 | 行号 | 说明 |
|---|---|---|
DownLoadTemplate() | :539 | EPPlus 生成导入模板 |
Import(files) | :548 | ValidationImportFile 校验 → 事务内写入(:582),支持明细表导入(:585 isDetailImport) |
Export(pageData) | :670 | pageData.Export = true,配合 Columns 保证导出列与界面一致 |
Upload(files) | :527 | 文件上传 |
前端:src/components/basic/UploadExcel.vue + ViewGrid 工具栏按钮(按钮权限在 src/api/buttons.js)。
8. 打印 🟡
- 前端:
src/components/VolPrint/VolPrint.vue+vue-plugin-hiprint.js(依赖 jquery/jsbarcode/socket.io-client/jspdf/html2canvas/canvg)+template.js(含isEnableMergeCell等表格属性)。模板设计器在src/views/print/print.vue。 - 后端:
VolPro.Core/Print/PrintCustom.cs。 - ViewGrid 集成:
src/components/basic/ViewGrid/ViewGridPrint.vue。
注意:
socket.io-client这个依赖说明 hiprint 的静默/批量打印需要本地客户端(hiprint 的 socket 打印服务)。浏览器直接打印没问题;ERP 常见的"连续打印多张单据、针式套打凭证"需要额外部署客户端或改用服务端生成 PDF。这是本项标黄的原因。
9. 审核流 ✅(两套,别选错)
| 引擎 | 位置 | 适用 |
|---|---|---|
| WorkFlow(图状工作流) | VolPro.Core/WorkFlow/:WorkFlowContainer.cs、WorkFlowDb.cs、Extensions/WorkFlowAddProccessExtensions.cs、WorkFlowAuditExtensions.cs、WorkFlowMessageExtensions.cs | 复杂流程图、条件分支 |
| FormWorkFlow(表单审批流) | VolPro.Core/FormWorkFlow/:FormWorkFlowManager.cs(SubmitWorkflow :155 / Audit :382)、FormWorkFlowNotify.cs | ERP 单据审批推荐用这个 |
接入方式:SaveModel.IsFlow 标记该单走流程;ServiceBase.Audit(keys, auditStatus, auditReason)(:741)→ keys.ProcessWorkflow(...)。
前端:src/components/basic/ViewGrid/ViewGridAudit.vue、ViewGridAuditSign.vue(会签/签章)、ViewGridAuditNodeList.vue、ViewGridAuditConfig.jsx、ViewGridAuditHis.vue;流程设计器在 src/views/sys/formflow/、src/components/workflow/(jsplumb 连线)。
10–11. 自定义列格式 / 自定义查询条件 ✅
- 自定义列(用户自选显示列、顺序、宽窄):
src/components/basic/ViewGrid/ViewGridCustomColumn.vue+.js。 - 自定义查询:
src/components/basic/VolCustomSearch/(VolCustomSearch.vue、VolCustomFields.vue、VolCustomFilter.vue、cache.js)——用户自己挑字段、设操作符、保存查询方案。 - 列格式:
VolTableFormat.js+ 列配置的formatter/ jsxrender;另有src/views/table/tableFormat.vue演示"格式化+背景颜色+提示"。
12. 上下游数据关联加载 🟡
框架不提供通用"单据流转引擎",但 ERP 示例给了完整可抄的范式:
src/views/erp/erp/ERP_InventoryIo/:purchaseInSetup.js(采购入库引用采购订单)、saleOutSetup.js、ioPageSetup.js、ioDetailSetup.js、inCheckSetup.js、outCheckSetup.js- 后端库存事务:
VolPro.ERP/Services/erp/Stock/(ErpPurchaseInboundHelper.cs、ErpSaleOutboundHelper.cs、ErpInventoryStockService.cs、ErpStockConstants.cs) - 选单通用组件:
src/components/basic/VolSelectTable/、VolSelectBox/
判断:这是业务开发工作量,不是框架能力缺口。框架提供了弹窗选单组件 + 主子表事务 + Partial 扩展位,你要做的是为每个单据对(订单→入库→发票→付款)写选单规则、数量拆分、反写与关单逻辑。
13. 文件存储 OSS 🔴(唯一硬缺口)
这是评估中唯一确认没实现的项:
src/components/basic/VolUpload.vue:65——// import OSS from 'ali-oss'已被注释- 同文件 :76-77 ——
// 旧逻辑里用到 window.oss,这里仅保留占位/const OSS = {}; - 同文件 :396-398 ——
const uploadOSS = async () => { // 保留扩展点 }空函数 - 图片回显走
:297(proxy.$global.oss?.url || http.ipAddress),$global.oss是可配置的,说明框架预留了开关
后端 ServiceBase.Upload()(:527)只写本地磁盘 + appsettings.json 的 VirtualPath.StaticFile。package.json 里 ali-oss: ^6.23.0 还在,但没被用起来。
工作量评估:约 1–2 人日。改造点三处——后端加 OSS Service(或改用 MinIO SDK)、
VolUpload.vue的uploadOSS()填实(STS 临时凭证直传最稳)、$global.oss.url配成 CDN 域名。建议直接换 MinIO,私有化部署对 ERP 客户更友好。
14–17. 消息推送 / 审核流推送 / 邮件 / 定时任务 ✅
- SignalR:
VolPro.Core/SignalR/MessageHub.cs(站内消息,挂在/hub/message)、VolPro.WebApi/Controllers/Hubs/HomePageMessageHub.cs;前端src/views/signalR/Index.vue,开关appsettings.json的UseSignalR: "true"。 - 审核流推送:
VolPro.Core/FormWorkFlow/FormWorkFlowNotify.cs+WorkFlow/Extensions/WorkFlowMessageExtensions.cs—— 节点到达时写待办 + SignalR 推送。 - 邮件:
VolPro.Core/Utilities/MailHelper.cs+VolPro.Core/BackgroundServices/mail/MailService.cs/MailBackgroundService.cs(后台队列异步发送,不阻塞请求),配置在appsettings.json的Mail节点。 - 定时任务:
VolPro.Core/Quartz/完整实现(QuartzNETExtension.cs提供AddJob/Remove/Update/Pause/Start/Run/TriggerAction,即界面上可增删改启停与立即执行);数据表Sys_QuartzOptions/Sys_QuartzLog(执行日志);任务类型有HttpResultfulJob.cs(HTTP 回调)+IOCJobFactory.cs(反射调本地方法)+QuartzFileHelper.cs(脚本)。
集群注意:Quartz 用内存调度器(
QuartzNETExtension未接入持久化 JobStore),多实例部署会重复执行。ERP 若做负载均衡,需要给 Quartz 补 ADO.NET JobStore 或改成单实例跑任务。
三、额外确认到的 ERP 刚需(都是白送的)
| 能力 | 证据 |
|---|---|
| 单据编码自动生成 | ServiceBase.cs:154 mainEntity.CreateCode() |
| 并发/乐观锁 | SaveModel.DataVersionField/Value |
| 扩展字段(客户自定义字段) | PersistExtendFields / LoadExtendFields + src/views/builder/extendField/ |
| 数据权限(只看自己的数据) | appsettings.json UserAuth + VolPro.Core/Tenancy/ |
| 多租户/动态分库 | UseDynamicShareDB、DBPath、VolPro.Core/Tenancy/ |
| 字段级权限 | ViewGridInitButtonsAuthFields.jsx、saveAuthFields |
| 审计日志 | ServiceBase.cs:309 "审计日志" + VolPro.Core/Middleware/ActionLog.cs |
| 多数据库 | SqlServer/MySql/PgSql/Oracle/达梦/金仓/GaussDB/OceanBase(VolPro.Core/DbSqlSugar/SqlSugarDbType.cs) |
| 钉钉/企微/微信 | VolPro.Core/WeChat/(微信模板消息),钉钉企微未见封装 |
四、风险与建议
三个必须提前决策的点:
- OSS 自建(1–2 人日)。建议 MinIO 而非阿里云,私有化友好。
- 打印方案(2–5 人日)。若客户要针式套打/连续打印,评估 hiprint 客户端部署成本,或改服务端 PDF。
- Quartz 集群重复执行。ERP 上生产若多副本,必须处理。
两个容易低估的成本:
- ERP 示例不能直接当产品。42 个实体看着全,但库存计价(加权平均/移动平均)、成本结转、往来核销、账期与账龄、税率与含税单价这些真实 ERP 的核心,示例里是简化版或没有。这块的建模与代码量远大于框架本身的配置工作。
- 前端主子表交互的定制深度。标准明细是"表格内逐行编辑",但 ERP 单据常有批次/序列号、辅助单位、多税率、整单折扣分摊——这些都要在
src/extension/**/*.jsx里写,且生成器的"安全区"机制要求你严格只改 jsx,否则重新生成会被覆盖。
建议路径:先用 src/views/builder/coderV3.vue 代码生成器把你的真实单据表结构生成出来(实体 + Service + Controller + Vue 页面 + 菜单),在生成的骨架上,按 ERP 示例 ERP_InventoryIo/ 的范式写上下游流转,最后补 OSS 与打印。框架的生成器 + extension/ jsx + Partial/ 这套"生成区/手写区分离"机制是整个方案能落地的关键,务必先吃透。