一、引言模块开发是通达OA二次开发的核心内容。本文将通过一个完整的实战案例详细介绍如何创建一个功能完善的OA模块包括目录结构、数据库设计、代码编写、菜单注册和权限分配等环节。二、开发前准备2.1 需求分析假设我们需要开发一个项目管理模块包含以下功能2.2 数据库设计项目表project字段名类型说明project_idint项目ID主键自增project_namevarchar(100)项目名称descriptiontext项目描述start_datedate开始日期end_datedate结束日期statustinyint状态0进行中1已完成creator_uidint创建人IDcreate_timedatetime创建时间update_timedatetime更新时间数据库关系图三、模块开发步骤3.1 步骤一建立模块目录在MYOA\webroot\general目录下创建模块目录New-Item -ItemType Directory -Path MYOA\webroot\general\project目录结构规划project/ ├── index.php # 项目列表页 ├── add.php # 添加项目页 ├── edit.php # 编辑项目页 ├── detail.php # 项目详情页 ├── delete.php # 删除项目接口 ├── ajax.php # AJAX接口 └── style.css # 模块样式文件3.2 步骤二创建数据库表使用phpMyAdmin或SQL语句创建表CREATE TABLE IF NOT EXISTS project ( project_id int(11) NOT NULL AUTO_INCREMENT, project_name varchar(100) NOT NULL, description text, start_date date DEFAULT NULL, end_date date DEFAULT NULL, status tinyint(1) DEFAULT 0, creator_uid int(11) NOT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (project_id), KEY creator_uid (creator_uid) ) ENGINEInnoDB DEFAULT CHARSETutf8;3.3 步骤三编写核心代码3.3.1 项目列表页index.php?php $HTML_PAGE_TITLE _(项目管理); include_once(inc/auth.inc.php); include_once(inc/header.inc.php); $td new TD(); // 分页参数 $page isset($_GET[page]) ? intval($_GET[page]) : 1; $page_size 10; $offset ($page - 1) * $page_size; // 查询项目列表 $sql SELECT p.*, u.name AS creator_name FROM project p LEFT JOIN user u ON p.creator_uid u.uid ORDER BY p.create_time DESC LIMIT $offset, $page_size; $result $td-query($sql); // 查询总数 $count_sql SELECT COUNT(*) AS total FROM project; $count_result $td-query($count_sql); $count_row $td-fetch_array($count_result); $total $count_row[total]; $total_pages ceil($total / $page_size); ? div classmain-content h2?php echo _(项目列表); ?/h2 a hrefadd.php classbtn btn-primary ?php echo _(添加项目); ? /a table classtable thead tr th?php echo _(项目名称); ?/th th?php echo _(描述); ?/th th?php echo _(时间范围); ?/th th?php echo _(状态); ?/th th?php echo _(创建人); ?/th th?php echo _(操作); ?/th /tr /thead tbody ?php while ($row $td-fetch_array($result)) { ? tr td?php echo $row[project_name]; ?/td td?php echo csubstr($row[description], 0, 50); ?/td td?php echo $row[start_date] . ~ . $row[end_date]; ?/td td?php echo $row[status] ? _(已完成) : _(进行中); ?/td td?php echo $row[creator_name]; ?/td td a hrefdetail.php?id?php echo $row[project_id]; ? ?php echo _(查看); ? /a a hrefedit.php?id?php echo $row[project_id]; ? ?php echo _(编辑); ? /a a hrefdelete.php?id?php echo $row[project_id]; ? onclickreturn confirm(?php echo _(确定删除?); ?) ?php echo _(删除); ? /a /td /tr ?php } ? /tbody /table ?php // 分页代码省略 ? /div ?php include_once(inc/footer.inc.php); ?3.3.2 添加项目页add.php?php $HTML_PAGE_TITLE _(添加项目); include_once(inc/auth.inc.php); include_once(inc/header.inc.php); if ($_POST) { $td new TD(); $project_name $td-escape($_POST[project_name]); $description $td-escape($_POST[description]); $start_date $_POST[start_date]; $end_date $_POST[end_date]; $creator_uid $_SESSION[uid]; $sql INSERT INTO project (project_name, description, start_date, end_date, creator_uid) VALUES ($project_name, $description, $start_date, $end_date, $creator_uid); if ($td-query($sql)) { Message(_(添加成功), index.php); exit; } else { Message(_(添加失败), add.php); exit; } } ? div classmain-content h2?php echo _(添加项目); ?/h2 form methodpost actionadd.php div classform-group label?php echo _(项目名称); ?:/label input typetext nameproject_name required classform-control /div div classform-group label?php echo _(项目描述); ?:/label textarea namedescription classform-control/textarea /div div classform-group label?php echo _(开始日期); ?:/label input typedate namestart_date required classform-control /div div classform-group label?php echo _(结束日期); ?:/label input typedate nameend_date required classform-control /div button typesubmit classbtn btn-primary ?php echo _(提交); ? /button a hrefindex.php classbtn btn-default ?php echo _(返回); ? /a /form /div ?php include_once(inc/footer.inc.php); ?3.3.3 删除项目delete.php?php include_once(inc/auth.inc.php); $td new TD(); $project_id isset($_GET[id]) ? intval($_GET[id]) : 0; if ($project_id 0) { $sql DELETE FROM project WHERE project_id $project_id; if ($td-query($sql)) { Message(_(删除成功), index.php); } else { Message(_(删除失败), index.php); } } else { Message(_(参数错误), index.php); } ?3.4 步骤四注册菜单在通达OA系统管理中注册菜单Mermaid 渲染失败: Lexical error on line 9. Unrecognized text. ...al/project/index.php] E --|父菜单| E3[ -----------------------^菜单注册信息字段值菜单名称项目管理菜单地址/general/project/index.php父菜单工作台或其他合适的父菜单菜单图标选择合适的图标排序号根据需要设置3.5 步骤五分配权限权限分配步骤进入系统管理 → 角色管理选择需要分配权限的角色点击编辑权限在权限列表中找到项目管理并勾选保存权限设置四、高级功能开发4.1 附件上传功能使用OA内置的文件上传函数?php include_once(inc/utility_file.php); // 处理文件上传 if ($_FILES[attachment][name]) { $attach upload(attachment, 0, 0, project); if ($attach[error] 0) { $attach_id $attach[id]; // 保存附件ID到数据库 } } ?4.2 人员选择组件使用OA的人员选择组件?php include_once(inc/header.inc.php); ? !-- 人员多选组件 -- input typehidden nameuser_ids iduser_ids script typetext/javascript // 调用人员选择组件 selectUser(user_ids, multi); /script4.3 AJAX交互?php // ajax.php include_once(inc/auth.inc.php); $action isset($_GET[action]) ? $_GET[action] : ; if ($action search) { $keyword $_GET[keyword]; $td new TD(); $keyword $td-escape($keyword); $sql SELECT * FROM project WHERE project_name LIKE %$keyword%; $result $td-query($sql); $data array(); while ($row $td-fetch_array($result)) { $data[] $row; } echo json_encode($data); exit; } ?五、调试与测试5.1 调试方法调试工具工具用途php_errors.logPHP错误日志浏览器开发者工具前端调试phpMyAdmin数据库查询var_dump()变量输出5.2 测试用例功能测试测试项测试步骤预期结果添加项目填写表单提交项目成功添加编辑项目修改信息提交项目信息更新删除项目点击删除确认项目成功删除列表显示访问列表页显示所有项目权限控制无权限用户访问提示无权限六、模块部署与发布6.1 部署流程6.2 发布清单项目说明代码文件所有PHP文件样式文件CSS文件数据库脚本SQL文件配置文件菜单配置权限配置角色权限七、最佳实践总结7.1 代码规范编码规范规范项要求变量命名驼峰式命名文件命名小写字母下划线分隔数据库表小写字母下划线分隔SQL语句使用TD类的escape方法转义7.2 安全注意事项输入验证对所有用户输入进行验证SQL注入使用参数化查询或escape方法文件上传验证文件类型和大小权限控制使用auth.inc.php进行权限验证敏感信息不输出敏感信息到页面