
泛微系统门槛说高不高说低也不低。很多刚接触e-cology的人拿着实施手册啃了半天遇到“流程提交后看不到待办”“按钮权限莫名其妙失效”“报表取数对不上”这类问题时还是会一脸懵。原因很简单泛微的很多功能看似是界面上的配置底子里全是数据库表在撑着。搞懂泛微常用数据表就像拿到了一张内部地图排查问题、做二次开发、写SQL报表时心里会踏实很多。这篇文章我把这些年在e9、e10项目里频繁用到的核心表梳理一遍结合实战中踩过的坑一起聊。1. 泛微数据表体系与命名规律1.1 先分清三大引擎流程、表单、建模泛微e-cology也就是e9、e10这些版本的设计思路是把OA里所有业务抽象成三样东西流程、表单、建模。这三样东西在界面上是分开配置的在数据库里也是分开存储的但彼此之间又有千丝万缕的关联。流程负责驱动表单负责承载数据建模则用来做基础档案和自定义业务对象。比如你建一个“费用报销”流程流程引擎里有它的审批节点、路由条件单据上填的报销事由、金额存到表单的数据表里而报销单里选择的“成本中心”“客户档案”往往来自建模引擎配置的档案表。理解了这三个引擎再去看数据库里的表名思路就清晰了。流程相关的表以workflow_开头表单相关的表叫formtable_main_表ID和formtable_detail_表ID建模相关的表则是由建模引擎动态生成元数据存在modeinfo里具体数据表的名字在配置建模时自己指定。我见过不少人分不清“建模表”和“表单表”的区别。简单说流程表单是跟着流程走的数据一定要有流程实例才能产生而建模表是独立的类似于自建的业务数据库表可以单独增删改查。搞清楚这一点后面对表结构才不会乱。1.2 表ID的识别与关联思路泛微每建一张流程表单系统会自动生成一个表单ID在表名里直接体现出来。比如你的报销表单ID是66那主表就是formtable_main_66如果有明细表明细表就是formtable_detail_66。这个ID在流程设计器的“表单ID”字段里能看到也可以用SQL查出来-- 查表单ID根据流程名称反查 SELECT b.id AS formid, b.formname FROM workflow_base w LEFT JOIN workflow_formbase b ON w.formid b.id WHERE w.workflowname LIKE %报销%;建模表稍微特殊一点。建模配置时你可以自己指定表名所以它不是统一的modeinfo_xxx这种形式而是你起的业务表名。元数据信息却在modeinfo表里。比如我建了一个“客户档案”建模表表名叫customer_info那么真正的数据是存在customer_info这张表里的而这张表的字段定义、列表页配置、权限设置全部记录在modeinfo、modefields、modepriview这些表里。这个设计有个坑迁移环境或者做数据同步时光备份业务数据表没用modeinfo里的元数据同步不过去新环境里建的表就是“死表”——有数据但建模菜单里看不见必须把元数据也一起处理。2. 流程引擎核心表工作流数据的来龙去脉2.1 workflow_base流程的身份证流程相关的表最常用的是workflow_base。它存的是流程的静态定义每条记录代表一个流程图。最关键的几个字段id流程ID很多地方叫workflowid、workflowname流程名称、formid关联的表单ID、isvalid是否有效、version流程版本号。实操里最频繁的场景是通过流程名称反查流程ID或者确认一个流程到底绑定了哪张表单。上面给的SQL就是干这个用的。还有一点值得注意泛微的流程升级后会生成新版本同名的流程会有多条记录version字段能帮你区分当前生效的版本。很多时候你改了流程测试环境里却还是老版本在跑就是因为在代码块或者集成接口里写死了旧流程ID。配合同样重要的还有workflow_node存的是流程节点信息。workflowid关联流程IDnodeid是节点ID在流程设计器里能看到nodename是节点名称。做待办统计、节点耗时分析、或者定位“这个节点为什么没有审批人”的时候都要靠这两张表联查。-- 查某流程的所有审批节点 SELECT n.nodeid, n.nodename, n.isstart, n.isend FROM workflow_node n WHERE n.workflowid 123 ORDER BY n.nodeid;2.2 流程实例与待办requestbase 和 currentoperator流程跑起来之后每发起一次就是一个流程实例存在workflow_requestbase里。这张表相当于流程实例的总台账requestid是实例ID流程表单详情页URL里能看到那个数字workflowid流程ID、creater创建人ID、createdate、requestname申请事项名称比如“张三的费用报销单”、currentnodeid当前停留节点都是排查问题的高频字段。还有一张表做待办查询时必须打交道workflow_currentoperator。它存的是当前所有未办结的待办任务requestid、nodeid、userid待办人ID、receivedate收到时间、isremark是否已读这些字段。很多人写“我的待办”报表直接联这张表就对了。这里有一个经典误区和大家分享workflow_currentoperator只记录当前未处理的任务流程一旦走下个节点记录就变了想查历史流转记录得去workflow_requestlog或workflow_flashupload这些日志表。我曾经遇到一个客户要做“全流程待办时长分析”一开始用 currentoperator 关联历史数据怎么都对不上后来才明白这是“瞬间态”的表做历史分析得换一张思路。2.3 表单数据与流程数据的桥 insertformtable 系列业务流程的数据最终落在表单表里但表单表本身不带流程信息。泛微通过insertformtable这个系列的表来建立表单数据与流程实例之间的桥接常用的有insertformtable主表映射、insertformtabledetail明细映射。简单理解它们存的是“哪条流程实例对应哪条表单主表记录”。实际开发中经常需要从表单主表反查流程ID或者从流程ID查表单记录SQL这样写-- 根据流程实例ID查报销单主表数据 SELECT f.* FROM formtable_main_66 f INNER JOIN insertformtable i ON f.id i.formtableid WHERE i.requestid 12345;这个桥接表在集成外部系统时特别有用。比如HR系统要同步“员工入职流程”数据光查formtable_main_xx查不到流程状态必须通过insertformtable关联workflow_requestbase才能知道这条数据当前走到哪个节点、是否已归档。常见坑提示表单数据删除或流程实例被清理后insertformtable里可能还有残留记录导致关联时出现脏数据。做报表前最好加条件过滤“isvalid 1”之类的有效标记各版本字段略有差异以实际环境为准。3. 表单与明细表业务数据的物理存储3.1 主表、明细表如何设计字段创建流程表单时界面上你拖了一个“文本框”“日期框”“下拉框”数据库里对应的表结构会自动生成。这是泛微最大的特点表单配置完之后表结构就确定了。字段命名规则跟你添加的“字段名称”直接相关比如你加了一个名为“报销事由”的字段数据库里的列名很可能就是baoxiaoshiyou或拼音首字母。明细表的设计思路是“一对多”。主表记录单据头明细表记录单据体。两张表通过mainid这个字段关联。比如报销单主表 id100对应明细表里可能有多条记录它们的mainid都是100。实操中很多人报表取数时容易犯一个错直接把明细表和主表 LEFT JOIN导致主表数据被明细数据撑成多行。正确的做法是先明确你要的粒度查“单据数”就以主表为主查“明细行数”就以明细表为主。遇到客户说“报销统计怎么多了一倍数据”十有八九是这里出了问题。3.2 明细表字段类型与下拉框的处理细节泛微明细表里的字段类型比如下拉框跟主表的下拉框有个明显的区别明细表字段如果被修改类型比如从“下拉框”改成“文本框”在数据库层面可能只是改了一个字段类型但在前端渲染和数据存储行为上会发生连锁反应。我在一个e9项目里遇到过一个真实故障客户要改明细表“费用类型”字段的下拉框选项实施同事直接在字段设置里改了选项集合保存后前台没生效报表里的数据也错乱了。排查了半天发现是因为他把字段类型从“下拉框”改成了“下拉多选”导致数据库存的值从字符串变成了带分隔符的多选值原先的单选统计逻辑全部作废。所以这里提醒一句修改字段类型前先确认是否已经有历史数据。有历史数据的字段尽量不要改类型而是新增一个字段替代实在要改必须写SQL处理存量数据。尤其涉及下拉框的显示值和真实值映射要查workflow_formfield里的fieldtype和fieldhtmltype字段确认。3.3 默认值设置藏在两张表里表单字段的默认值在界面上看是在表单设计器里配的但实现机制上有两种一种是在表单设计器里配的固定默认值或JS默认值另一种是通过“字段属性”里的默认值公式设定的。无论哪一种底层都会写入workflow_formfield表的defaultvalue字段。但这里有个细节流程表单的默认值不一定能在数据库里直接改生效。因为泛微在发起流程时前端会用JS动态填充默认值而不是后端读取defaultvalue写入。所以如果你在数据库里改了默认值想要对已有流程生效多半要配合代码块或者重新保存表单才可靠。举个例子客户希望“申请日期”默认为当天并且不允许用户修改。界面配置基本就能搞定。但如果希望“申请编号”根据某个规则自动生成且要保证并发环境下不重复那就不能靠默认值了得在流程的“表单初始化”代码块里写Java逻辑或者在提交时用代码块生成编号并写回表单字段。心得分享涉及默认值的需求先问清楚“是用户发起时自动填还是保存时自动填还是提交后填”三种场景的技术方案完全不同。单纯配默认值只能解决“发起时自动显示”保存、提交时自动赋值一定要上代码块。4. 建模引擎数据表可视化背后的SQL记忆4.1 modeinfo表建模配置的“户口本”建模引擎是泛微OA里很有价值的功能很多客户不喜欢用流程表单去承载主数据而是用建模来管理“客户档案”“项目台账”“设备台账”等基础信息。建模的灵活性在于表结构可以自己定义字段增删改查比表单表更自由。modeinfo表记录的就是每一个建模表的元数据。id是建模IDmodename是建模名称tablename是物理表名比如customer_infoviewpage是指向的列表视图页面。如果你写SQL查数据首先要知道你要查的物理表名可以用这条SQL先确认-- 查所有建模表的物理表名 SELECT id, modename, tablename FROM modeinfo WHERE isvalid 1;拿到后再去查对应的物理表数据。很多刚接触泛微的人看到建模数据一直查不出来就是因为直接拿“建模名称”当表名去查了实际上物理表名跟建模名称是可以脱钩的。配置建模时系统会让你填“表名”这个填的值才是真正的数据库表名。4.2 创建数据表并插入数据建模的快路径热词里提到的“创建数据表并插入数据”在泛微里有两条路径。一条是在建模模块里手动配置系统自动生成表结构然后通过界面录入或导入Excel插入数据。另一条是直接用SQL创建物理表再用“外部数据源/集成”方式接入建模菜单。后者灵活但坑多表结构不规范时泛微会读不出字段。我自己的做法是能用建模配置创建的就绝不用SQL建表。因为建模配置会自动生成字段元数据、列表搜索、权限控制等配套信息直接SQL建表后这些东西全要手工补工作量反而更大。如果一定要SQL批量插数据推荐先在建模里建好表然后用SQL往物理表插-- 往建模表 customer_info 批量插入数据仅示例字段以实际为准 INSERT INTO customer_info (field1, field2, field3, creater, createdate) SELECT ... FROM source_table;插入时注意字段类型泛微的日期字段一般建议存字符串YYYY-MM-DD主键用自增ID别自己造ID。我在一个项目里吃过亏程序生成的ID跟泛微自增ID冲突在详情页打开记录时直接报错。4.3 e9流程自动赋予客户查询权限的底层逻辑热词里有一条很典型的业务需求“e9流程选择了客户之后会自动给流程相关人员赋予客户查询权限”。这个功能听着神秘拆开来看本质是建模权限表和数据操作代码块的组合效果。具体来说流程表单里通常会有一个“客户”浏览框这个浏览框绑定的是客户建模表比如customer_info。用户发起流程时选择了某条客户记录提交动作触发后会在代码块里调用给该客户分配权限的接口把当前流程节点、参与人、后续审批人写入到客户建模的权限表里。泛微建模权限相关的核心表是modepriview。这张表记录的是“谁能看哪条建模数据”常见字段包括formid建模ID、usertype授权类型人员/角色/部门、userid被授权主体ID、scopeid数据范围ID即具体哪条数据。流程自动给相关人员授权其实就是往这张表里插记录-- 查询某建模下所有授权记录 SELECT * FROM modepriview WHERE formid 88;理解了这个逻辑当客户说“流程提交后相关人员还是看不到客户档案”时排查思路就清晰了先看modepriview里有没有写入授权记录再看授权主体是具体人员还是部门角色最后看是代码块没触发还是人员ID传错了。这三个环节层层排查多数问题都能定位。实操提醒写这种授权代码块时务必注意重复授权的问题。同一流程反复提交时要在授权前先做一次去重判断否则modepriview里会积累一堆重复记录数据量大以后查询和权限判断都会变慢。5. 常用系统表与登录、权限相关细节5.1 组织架构与人员身份三张表提到权限就绕不开人和部门。泛微里最常用的人员表是hrmresource这是人力资源基础表几乎每个报表都要关联。id是人员内部IDloginid是登录名lastname是姓名departmentid是部门IDsubcompanyid1是分部IDstatus是人员状态在职/离职。跨系统集成时外部系统往往只认登录名但内部关联时应该用人员ID。部门表是hrmdepartment存部门ID和部门名称。上级部门关系是靠supdepid字段自关联实现的。查询部门层级时如果只用一层LEFT JOIN会漏掉多级子部门数列部门人数、部门预算时经常出现“统计不全”的尴尬。还要提一张表sec_user这是登录账户表跟hrmresource通过id关联。登录密码的哈希值、账户锁定状态、最后登录时间都存在这里。热词里提到“登录时长设置”其实指的是系统参数和session超时时间配置并不直接存在sec_user里而是由系统配置文件或sys_parameter表控制。5.2 系统参数与租户配置的查看方法泛微不少系统级配置可以通过运维平台设置但很多参数在数据库里也能查到。比如sys_parameter表各版本命名略有不同中记录着系统运行的全局参数。密码策略、会话超时时间、文件上传大小限制等都可能在这里体现。举个例子客户反馈“OA登录后过一会儿就掉线”要排查的就是session超时设置。Web端和移动端的超时机制不完全一样Web端多见于web.xml里的session-timeout和系统面板登录超时设置移动端则看token的有效期配置。直接查数据库可以确认真实值-- 查看系统参数以实际版本表名为准 SELECT * FROM sys_parameter WHERE parametername LIKE %timeout%;这里提醒一下不同版本和部署方式的参数表名、字段差异不小实施前最好先确认自己环境的表结构不要照搬网上的SQL。5.3 建模列表视图和搜索条件的存储建模引擎还有一个常用却容易被忽略的表是modedataview。它记录的是建模的列表视图配置。每新建一个“列表页样式”就对应一条或多条modedataview记录里面包含视图名称viewname、视图条件viewcondition、排序字段、以及列的显示配置。利用这张表可以在不动前端的情况下通过修改视图条件来实现一些“隐藏数据”的效果。比如车主页面上能看到客户列表但某个视图只显示“本部门创建的客户”那就在视图条件里预制部门过滤条件。排查“为什么这个视图看不到数据”时优先检查viewcondition字段的过滤条件比在前端反复试更高效。遇到过一个案例客户在建模里新建了一个视图设置了筛选条件“创建人当前用户”结果某领导登录后视图空白。排查到最后发现这个视图的创建人字段配置错了存的是“最后修改人”而不是“创建人”导致只有恰好最后修改过记录的人才能看到。别笑这种低级错误在真实项目里出现频率不低。6. 高频实战问题与排查速查6.1 流程相关的高频SQL场景“获取流程id”是热词里出现频次最高的需求。下面汇总几种常见做法通过流程名称查ID拿workflow_base按workflowname过滤。通过表单数据反查流程ID走insertformtable桥接。通过流程实例ID查当前待办人用workflow_requestbase关联workflow_currentoperator。-- 查某流程实例当前环节的所有待办人 SELECT u.lastname AS 待办人, n.nodename AS 当前节点 FROM workflow_requestbase rb INNER JOIN workflow_currentoperator co ON rb.requestid co.requestid INNER JOIN workflow_node n ON rb.workflowid n.workflowid AND co.nodeid n.nodeid INNER JOIN hrmresource u ON co.userid u.id WHERE rb.requestid 12345;这类SQL写顺手之后日常排查效率会提升很多。但注意一点多节点并行审批时workflow_currentoperator可能同时有多条记录对应多个并行的节点。如果想只取主审批链路还得结合workflow_node里的节点类型过滤。6.2 过滤框隐藏字段与公式计算的处理思路热词里提到的“流程插入代码块根据筛选框隐藏字段”在实现上属于前端交互逻辑。比如当筛选框选择了“类型A”时要求隐藏明细表某些列或主表某些字段这种通常通过表单的JS代码块实现。不过要注意隐藏字段只是界面行为数据库里依然会提交值后端报表统计时别以为隐藏了就没数据。具体做法是在表单的“字段JS”里监听筛选框的change事件动态控制目标字段的显示或隐藏。如果要联动隐藏明细表的列需要操作明细表HTML表格的列代码稍复杂但核心还是前端DOM操作。隐藏字段在提交时建议同时置空避免脏数据进入表单表。合计字段计算公式是泛微表单的一个内置功能在字段属性里可以配置类似“本表金额字段累加”的公式。明细表数据变更后合计值应该自动刷新。如果合计值不变优先检查公式的“计算时机”设置其次检查明细表对应字段是否以正确的数字类型存储。泛微的自定义公式字段存储在表单表对应的列中排查时直接查主表里的合计字段值看数据库存储是否已经更新。6.3 常见问题速查表与避坑经验下面这些基于我的实际项目经验整理未必适用所有环境但可以作为排查方向的参考。现象可能原因排查思路流程已提交但审批人看不到待办待办写入失败或人员ID变更查workflow_currentoperator是否生成记录表单数据查不到流程相关信息表单表与流程表未关联通过insertformtable反查桥接关系建模列表看不到部分人员数据建模数据权限未分配查modepriview授权记录明细表修改下拉类型后历史数据异常字段类型变更导致存储重写恢复原类型新增替代字段合计字段值不变计算时机未触发或类型不匹配检查公式配置及列存储类型登录后频繁掉线会话超时配置过短查 session 超时和 token 有效期外部接口拿不到流程ID接口参数或流程版本问题先确认流程ID、再核对版本号避坑经验方面提醒三点一所有涉及表单表、建模表的操作先确认环境。泛微版本不同表名和字段差异不小生产环境的表结构和测试环境未必一致。二写SQL做批量更新之前一定先备份。我见过多次操作失误导致历史数据被覆盖最终只能靠备份恢复。别过度自信数据库操作前加个事务或导出一份备份是对自己负责。三能通过界面配置实现的需求不要轻易去改数据库。数据库表结构是泛微内部的实现细节版本升级时可能变化。改动越少升级越顺。7. 写在最后的几点体会泛微的数据表看起来多但常用的就那么几十张。把流程、表单、建模三大引擎对应的核心表摸清楚再熟悉一下人员组织表日常的开发、运维、报表需求基本都能覆盖了。我个人的经验是遇到一个“诡异”的问题先不要急着看前端代码或流程配置先去数据库里查一下数据本身。数据在表里是有的只是没显示出来那问题在前端或权限数据本身就缺失那就是流程逻辑或代码块没执行。这个方法论帮我省了大量排查时间。最后再分享一个小技巧做泛微报表或二次开发时用Navicat或DBeaver连接数据库把常用的联查SQL存成模板。等客户问“为什么报表数据不对”的时候运行一遍模板SQL20分钟内基本能定位到问题。这比打开流程设计器一处一处在界面上点要高效得多。