本文目录导读:

在PHP项目中实现合同管理,需要覆盖合同的全生命周期:创建、审批、签署、归档、履约监控,这是一个典型的企业级应用(如OA、CRM)功能。
下面我从数据库设计、核心功能模块、安全性和技术选型四个维度给出一个完整的PHP实现方案。
数据库设计(核心表结构)
这是合同管理的基石,建议至少包含以下三张核心表:
合同主表 (contracts)
| 字段名 | 类型 | 说明 |
|---|---|---|
id |
INT (主键) | 合同ID |
contract_no |
VARCHAR | 合同编号 (建议自动生成,如 HT-2024-0001) |
type_id |
INT | 合同类型 (外键,关联合同类型字典表) |
party_a |
VARCHAR | 甲方 (公司) |
party_b |
VARCHAR | 乙方 (客户/供应商) |
total_amount |
DECIMAL(10,2) | 合同金额 |
start_date |
DATE | 开始日期 |
end_date |
DATE | 结束日期 |
status |
TINYINT | 状态: 0-草稿, 1-审批中, 2-已生效, 3-已终止, 4-已归档 |
current_step |
INT | 当前审批步骤 (配合审批流程引擎) |
sign_method |
TINYINT | 签署方式: 1-电子签, 2-纸质签 |
created_by |
INT | 创建人ID |
created_at |
DATETIME | 创建时间 |
合同附件表 (contract_attachments)
| 字段名 | 类型 | 说明 |
|---|---|---|
id |
INT | |
contract_id |
INT | 合同ID |
file_name |
VARCHAR | 原始文件名 |
file_path |
VARCHAR | 存储路径 (或OSS URL) |
file_type |
VARCHAR | 类型 (如 pdf, docx, img) |
is_signed |
TINYINT | 是否为已签章版本 |
审批记录表 (contract_approvals)
| 字段名 | 类型 | 说明 |
|---|---|---|
id |
INT | |
contract_id |
INT | 合同ID |
approver_id |
INT | 审批人ID |
step |
INT | 审批步骤 (1,2,3...) |
status |
TINYINT | 0-待审批, 1-通过, 2-驳回 |
comment |
TEXT | 审批意见 |
operated_at |
DATETIME | 操作时间 |
核心功能模块实现
合同创建 & 编辑(CRUD基础)
- 表单设计:使用 Laravel/ThinkPHP 等框架的验证器,验证必填项(金额、日期、双方主体)。
- 合同编号:在
模型的creating事件中自动生成,防止重复。// Laravel 示例 protected static function booted() { static::creating(function ($contract) { $contract->contract_no = 'HT-' . date('Ymd') . '-' . str_pad(Contract::count() + 1, 4, '0', STR_PAD_LEFT); }); } - 文件上传:使用
Laravel Storage或ThinkPHP Filesystem。建议:将合同文件上传到云OSS(阿里云/腾讯云),并做病毒扫描 + PDF/A 格式转换。
审批流引擎(核心难点)
不要硬编码 if-else,采用配置化的审批流。
实现思路(简单版):
- 创建一个
approval_flows表,定义每个合同类型需要经过几级审批。 - 在
contracts表中记录current_step。 - 当创建合同后,状态变为“审批中”,
current_step = 1。 - 开始审批时,查询当前步骤的审批人是谁(从用户表或角色表)。
- 每个审批动作(通过/驳回)操作:
- 通过:更新
contract_approvals状态为通过;更新contracts.current_step = step + 1;如果当前步骤是最后一步,则将contracts.status改为已生效。 - 驳回:将
contracts.status改回草稿,并清空current_step。
- 通过:更新
代码片段(Laravel 伪代码):
public function approve(Request $request, $contractId)
{
$contract = Contract::findOrFail($contractId);
$user = auth()->user();
// 1. 检查权限:当前用户是否为当前审批步骤的审批人
// 2. 记录审批动作
Approval::create([
'contract_id' => $contractId,
'approver_id' => $user->id,
'step' => $contract->current_step,
'status' => 1, //通过
'comment' => $request->input('comment')
]);
// 3. 判断是否为最后一步
$totalSteps = ApprovalFlow::where('type_id', $contract->type_id)->count();
if ($contract->current_step >= $totalSteps) {
$contract->status = 2; // 已生效
$contract->current_step = 0;
} else {
$contract->current_step += 1;
}
$contract->save();
// 4. 触发通知(发送邮件/站内信通知下一步审批人)
return back()->with('success', '审批通过');
}
电子签章集成(高级功能)
- 技术路线:不要自己造轮子,集成 e签宝、法大大 或 腾讯电子签 的API。
- 核心步骤:
- 上传合同文件到服务商(Base64或URL)。
- 调用API创建签署流程(设置签署顺序、签署位置、印章类型)。
- 生成签署链接(给内部员工或外部客户)。
- 回调接收:服务商签署完成后,回调你的服务器,更新
contracts.sign_method和is_signed状态。 - 下载已签章文件,替换原有附件。
合同履约监控(提醒、变更、终止)
- 到期提醒:
- 实现方式:使用 PHP 的
cron定时任务(Laravel Schedule)。 - 逻辑:每天执行一次脚本,查询
end_date在 X 天内(如30天)且status为“已生效”的合同,向负责人发送邮件或企业微信通知。
- 实现方式:使用 PHP 的
- 合同变更:
- 不建议直接修改原合同记录,建议设计一个变更单(
contract_change_log)表,记录变更前后的内容,并走一个简化的审批流程。
- 不建议直接修改原合同记录,建议设计一个变更单(
- 合同终止/作废:
- 修改
status为 3-已终止,并记录终止原因、终止文件。
- 修改
技术选型与框架推荐
| 组件 | 推荐方案 | 理由 |
|---|---|---|
| PHP框架 | Laravel 或 ThinkPHP | Laravel 生态强大(队列、事件、通知),ThinkPHP 入门快。 |
| 数据库 | MySQL | 成熟稳定,支持事务和全文索引。 |
| 文件存储 | 阿里云OSS / 腾讯云COS | 高可用,不占用服务器硬盘,支持CDN加速。 |
| 全文搜索 | Elasticsearch | 如果合同量巨大,需要对标题、合同号、内容做模糊搜索。 |
| 电子签 | e签宝 / 法大大 | 国内主流,合规性有保障。 |
| 消息队列 | Redis / RabbitMQ | 处理大批量到期提醒、签章回调,防止服务阻塞。 |
| 权限控制 | RBAC (Role-Based Access Control) | 区分:合同起草人、部门审批人、财务审批人、法务、管理员。 |
安全性 & 合规性重点
- 数据权限:不要一个用户能看到所有合同。
- 使用 数据权限范围(Scope),如:用户只能看到“自己创建的”或“自己参与的”或“自己部门负责”的合同。
-
// Laravel Scope 示例 public function scopeUserContracts($query, $userId, $role) { if ($role == 'admin') { return $query; } return $query->where('created_by', $userId) ->orWhereHas('approvals', fn($q) => $q->where('approver_id', $userId)); }
- 敏感信息脱敏:合同中的银行账号、身份证号在日志和列表页需要脱敏显示(
621 *** 2222)。 - 审计日志:记录所有合同的关键操作(创建、修改金额、审批、下载),存入
audit_logs表,用于事后追溯。
总结建议
- 不要从零开始:如果你是个人或小团队,建议直接使用成熟的开源PHP OA系统(如Odoo的PHP移植版、或基于Laravel的ERP系统),在其基础上修改。
- MVP实现:先实现以下3个核心功能,再逐步迭代:
- 增删改查 + 文件上传。
- 简单的两级审批(经理 -> 老板)。
- 到期提醒(Cron Job)。
- 电子签是加分项:如果业务要求线上签署,必须用第三方API,不要自己实现电子签名。
如果需要更具体的代码示例(如某个模块的完整Controller逻辑),可以告诉我你的PHP框架(Laravel还是ThinkPHP),我可以提供更针对性的代码。