简介:《通达OA二次开发手册》面向具备PHP编程基础、需要定制Office Anywhere网络智能办公系统的技术人员与运维开发者,帮助其理解系统架构并完成功能扩展与业务适配。资源为1个PDF文档,压缩包约188KB,内容围绕开发环境搭建与数据库管理两条主线展开:环境部分讲解OfficeFPM、OfficWeb、PHP与MySQL的参数配置及三者协同关系,并剖析auth.inc.php、header.inc.php、common.inc.php、conn.php等核心文件在认证、页面头部、公共函数与数据库连接中的职责;数据库部分涵盖phpMyAdmin安装使用、表结构分析与备份恢复策略,并给出创建模块目录、菜单、权限分配及编码测试的完整流程。目前已有89人学习,适合作为二次开发入门与查阅的参考手册。
1. 通达OA二次开发手册:从“能改”到“改不坏”的分界线在哪
接手一套跑了三年的通达OA,业务部门丢过来一张需求单:请假单要按部门层级自动跳转审批,同时把数据同步到自建的人力系统。你打开服务器,看到的是 PHP 源码目录、MySQL 库、还有一堆没人敢动的历史补丁。这时候“通达OA二次开发”这六个字,就不是一个技术名词,而是一道选择题——是改源码,还是走挂载点,还是干脆外挂一套服务。
这份手册类文档真正要解决的问题,是让二次开发从“凭感觉改文件”变成“有边界、可回滚、能交接”的工程动作。它适合两类人:一类是刚接手通达OA、需要快速定位改哪里的人;另一类是已经改过几轮、被升级覆盖和补丁冲突折磨过的人。核心矛盾只有一个——通达OA是产品化交付的闭源体系,你动的每一刀,都要为下一次官方升级留后路。
2. 先搞清楚通达OA的二次开发边界:哪些能碰,哪些碰了会翻车
2.1 通达OA的目录结构与可干预层
通达OA的部署形态通常是 PHP + MySQL + Apache/Nginx,源码目录里几个关键位置决定了你能做什么。常见做法是先把目录职责分清楚,再决定动哪里。
| 目录/位置 | 典型职责 | 二次开发干预程度 |
|---|---|---|
| 根目录入口文件 | 请求分发、公共初始化 | 低,尽量不改 |
| 模块目录(如 hr、workflow) | 业务逻辑与页面 | 中,可挂载或覆写 |
| 公共类库目录 | 数据库、权限、工具类 | 低,改了影响全局 |
| 模板目录 | 页面渲染 | 中,可替换但注意升级 |
| 数据表 | 业务数据与配置 | 高,结构变更需谨慎 |
| 自定义挂载点/插件目录 | 官方预留扩展位 | 高,优先使用 |
这张表的意义在于:通达OA的二次开发不是“哪里都能改”,而是“优先用预留位,其次覆写,最后才动核心”。我一般会先确认当前版本有没有插件机制或钩子,如果有,所有需求优先往钩子上靠。
2.2 三种主流改造方式的选型对比
实际落地时,通达OA二次开发基本落在三条路径上,选错路径后面全是坑。
- 源码直接修改:找到对应 PHP 文件改逻辑。优点是快,缺点是升级必冲突,且没有回滚记录。
- 模板/视图覆写:只改前端展示和表单结构,不动业务逻辑。适合界面调整、字段增减。
- 外挂服务 + 数据同步:不动通达OA本身,通过数据库或接口做数据交换。适合跨系统集成、复杂计算。
选型判断标准很简单:如果需求涉及审批流转的核心逻辑,优先看官方工作流引擎是否支持配置;如果只是数据展示和采集,走模板覆写;如果是和外部系统对接,坚决走外挂服务,不要往通达OA里塞外部依赖。
提示:任何改动前,先做一次完整数据库备份和源码目录快照。通达OA的升级包通常会覆盖文件,没有快照就没有后悔药。
2.3 最小可复现的挂载改造示例
假设需求是:在请假单页面增加一个“紧急联系人”字段,并写入数据库。不改核心逻辑,走模板覆写 + 独立表存储。
// 文件:custom/leave_extend/leave_extra_field.php // 作用:在请假单渲染前注入额外字段,并处理提交 // 1. 注册模板变量(挂载到请假单视图) function leave_extend_assign(&$tpl) { // 从独立扩展表读取已有值 $sql = "SELECT contact FROM leave_extend WHERE leave_id = '" . intval($_GET['id']) . "'"; $row = DB::fetch_first($sql); $tpl->assign('emergency_contact', $row ? $row['contact'] : ''); } // 2. 处理提交(挂载到请假单保存后) function leave_extend_save($leave_id, $post_data) { $contact = trim($post_data['emergency_contact']); if ($contact === '') { return; // 非必填,空值不写入 } // 使用 REPLACE 保证同一请假单只存一条 $sql = "REPLACE INTO leave_extend (leave_id, contact) VALUES ('" . intval($leave_id) . "', '" . addslashes($contact) . "')"; DB::query($sql); }逻辑说明:这段代码不修改通达OA原有的请假单保存流程,而是在保存后追加一次写入。leave_extend是自建表,升级时不会被覆盖。参数上,leave_id用intval强制转整,contact用addslashes做基础转义,避免注入。如果通达OA版本支持参数化查询,优先用预处理语句替换字符串拼接。
参数调整点:如果字段需要必填,把空值判断改成返回错误;如果需要多字段,把 REPLACE 扩展成多列;如果请假单会被删除,记得在删除逻辑里同步清理扩展表。
3. 工作流二次开发:表单、节点、触发器的落地顺序
3.1 先画流程再动代码,顺序反了必返工
通达OA的工作流引擎是二次开发里最常被碰的部分。血泪经验是:很多人一上来就写触发器代码,结果流程节点还没定清楚,代码改了三版,流程还是跑不通。
正确顺序是:先在通达OA后台把流程节点、字段、权限配完,确认流程能手动跑通;然后再加触发器做自动化;最后才考虑用代码干预节点跳转条件。这个顺序能保证每一步都有可验证的中间状态。
3.2 触发器代码的挂载与调试
通达OA的工作流触发器通常支持在节点提交时执行自定义代码。常见做法是写一个独立 PHP 文件,在后台配置里引用。
// 文件:custom/workflow/leave_trigger.php // 作用:请假流程提交到部门经理节点时,自动判断天数并跳转 function leave_trigger_after_submit($flow_id, $run_id, $node_id, $form_data) { // 只处理请假流程 if ($flow_id != 18) { return; } // 提取请假天数(假设表单字段名为 leave_days) $days = floatval($form_data['leave_days']); // 天数大于 3 天,强制走总经理审批节点 if ($days > 3) { $next_node = 5; // 总经理审批节点 ID // 调用工作流引擎接口强制设置下一节点 WorkflowEngine::setNextNode($run_id, $next_node); } }逻辑说明:$flow_id是流程唯一标识,必须写死或从配置读取,避免影响其他流程。$form_data是当前节点提交的表单数据,字段名要和后台配置一致。setNextNode是示意接口,实际调用方式以当前通达OA版本的引擎 API 为准,常见做法是查官方开发文档或直接看工作流模块的源码调用方式。
参数说明:$days > 3这个阈值建议做成配置项,不要硬编码,否则业务规则一变就要改代码。$next_node的节点 ID 在流程设计器里能看到,改流程时节点 ID 可能变化,需要同步更新。
3.3 节点跳转条件的三种写法与适用场景
通达OA的工作流条件跳转,常见有三种实现方式:
- 后台配置条件:在节点出口条件里写表达式,适合简单字段判断,不改代码。
- 触发器代码判断:在提交后动态设置下一节点,适合复杂逻辑,但调试成本高。
- 外部接口回调:把表单数据发给外部服务,由外部返回跳转指令,适合跨系统决策。
选型建议:能用后台配置解决的,绝不写代码;后台配置表达不了的,优先用触发器;触发器需要外部数据支撑的,才走接口回调。每往下一层,维护成本翻一倍。
4. 数据库层二次开发:表结构变更与数据同步的避坑清单
4.1 通达OA数据表命名规律与扩展表设计
通达OA的数据表有比较固定的前缀和命名习惯,二次开发时不要直接改官方表结构,而是建扩展表。常见做法是:扩展表用独立前缀,通过主键关联官方表。
-- 创建请假扩展表,关联通达OA的 flow_run 表 CREATE TABLE `oa_leave_extend` ( `id` int(11) NOT NULL AUTO_INCREMENT, `run_id` int(11) NOT NULL COMMENT '关联 flow_run.run_id', `emergency_contact` varchar(64) DEFAULT '' COMMENT '紧急联系人', `sync_status` tinyint(1) DEFAULT 0 COMMENT '0未同步 1已同步', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_run_id` (`run_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;逻辑说明:run_id加唯一索引,保证一条流程实例只对应一条扩展记录。sync_status用于标记是否已同步到外部系统,避免重复推送。字符集用utf8mb4,和通达OA主库保持一致,避免乱码。
参数调整:如果业务需要多条扩展记录,去掉唯一索引,改成普通索引。如果同步频率高,可以加update_time字段做增量判断。
4.2 数据同步的幂等处理与失败重试
外挂服务同步数据时,最大的坑是重复推送和失败丢失。常见做法是:用sync_status做状态机,同步前先查状态,同步后更新状态,失败时记录错误并保留重试机会。
// 同步请假数据到外部人力系统 function sync_leave_to_hr($run_id) { // 1. 查扩展表,确认未同步 $sql = "SELECT * FROM oa_leave_extend WHERE run_id = " . intval($run_id) . " AND sync_status = 0"; $record = DB::fetch_first($sql); if (!$record) { return true; // 已同步或不存在,直接返回 } // 2. 调用外部接口(示意) $result = http_post('https://hr.internal/api/leave', json_encode([ 'run_id' => $record['run_id'], 'contact' => $record['emergency_contact'], ])); // 3. 根据结果更新状态 if ($result['code'] == 0) { DB::query("UPDATE oa_leave_extend SET sync_status = 1 WHERE id = " . intval($record['id'])); } else { // 记录错误日志,保留 sync_status = 0 等待重试 log_error('sync_leave_failed', $record['run_id'] . ':' . $result['msg']); } }逻辑说明:先查后推再更新,保证幂等。外部接口返回非成功时,不更新状态,下次定时任务会重新尝试。http_post是示意函数,实际用 curl 或框架 HTTP 客户端替换。
参数说明:重试频率建议用定时任务控制,比如每 5 分钟跑一次,避免频繁请求外部系统。错误日志要包含run_id和错误信息,方便排查。
4.3 避坑:通达OA二次开发中最容易翻车的 5 个点
现象一:升级后页面白屏。原因:直接改了核心文件,升级包覆盖后文件版本不匹配。 解决:所有改动走独立目录或挂载点,升级前对比文件差异,升级后重新挂载。
现象二:触发器代码不执行。原因:触发器文件路径配置错误,或函数名和后台配置不一致。 解决:在触发器入口加日志,确认代码是否被加载;检查后台配置的钩子名称是否和函数名完全匹配。
现象三:数据同步重复写入。原因:没有做幂等判断,定时任务和实时触发同时跑。 解决:加唯一索引或状态字段,同步前先查状态,同步后立即更新。
现象四:表单字段取不到值。原因:字段名和后台配置不一致,或表单数据在触发器执行时还未落库。 解决:在触发器里打印$form_data全量内容,确认字段名;如果数据未落库,改用流程结束后的事件。
现象五:MySQL 服务无法启动。原因:二次开发时改了表结构或字符集,导致 InnoDB 日志不兼容。 解决:改表前备份,改字符集时确保全库统一;如果已经启动失败,用innodb_force_recovery临时恢复后导出数据重建。
5. 升级不翻车的验证方法与一个具体技巧
5.1 升级前的兼容性自检清单
通达OA二次开发最怕的不是改代码,而是升级后不知道哪里坏了。我一般会在升级前跑一遍自检,确认所有自定义改动都有记录、有备份、有回滚路径。
| 检查项 | 确认方式 | 不通过的后果 |
|---|---|---|
| 自定义文件清单 | 对比官方包和当前目录 | 升级覆盖后功能丢失 |
| 数据库扩展表 | 导出建表语句 | 升级后表被删或字段冲突 |
| 触发器/钩子配置 | 截图后台配置 | 升级后配置重置 |
| 外部接口依赖 | 确认接口地址和密钥 | 升级后同步中断 |
| 备份完整性 | 实际恢复一次到测试环境 | 出问题无法回滚 |
这张表建议每次升级前过一遍,尤其是跨大版本升级时,官方可能调整目录结构或数据库字段。
5.2 用“影子表”做数据层灰度验证
一个具体技巧:在正式改扩展表之前,先建一张影子表,把新逻辑写入影子表,观察一段时间再切换。这样即使新逻辑有问题,也不影响正式数据。
-- 建影子表,结构和正式扩展表一致 CREATE TABLE `oa_leave_extend_shadow` LIKE `oa_leave_extend`; -- 新逻辑先写影子表 INSERT INTO oa_leave_extend_shadow (run_id, emergency_contact, sync_status) VALUES (1001, '张三', 0); -- 观察 3 天,确认数据量和业务逻辑无误后,切换代码写入正式表 -- 切换时把影子表数据合并回正式表 INSERT INTO oa_leave_extend SELECT * FROM oa_leave_extend_shadow WHERE run_id NOT IN (SELECT run_id FROM oa_leave_extend);逻辑说明:影子表的好处是零风险验证。新代码先写影子表,正式表不动,业务无感知。观察期结束后,用INSERT ... SELECT合并数据,再切换代码指向正式表。
参数说明:观察期根据业务频率定,低频流程可以拉长到一周。合并时用NOT IN避免重复,如果数据量大,改用LEFT JOIN判断。
5.3 我自己的习惯:改动必留三样东西
做了这么多轮通达OA二次开发,我养成了一个习惯:每次改动,不管多小,必须留三样东西——改动说明、回滚脚本、验证步骤。改动说明写清楚改了哪个文件、为什么改、影响范围;回滚脚本是能直接执行的 SQL 或文件替换命令;验证步骤是给接手的人看的,告诉他怎么确认改动生效了。
这个习惯救过我很多次。有一次升级后触发器不执行,就是因为半年前的一次改动没留说明,排查了两个小时才发现是钩子名称被改了。从那以后,我再也不相信“这次改动很简单不用记”。
希望帮到你。
本文还有配套的精品资源,点击获取