本文目录导读:

我来详细解释如何在PHP项目中实现“人工接管”功能,这通常指在自动化流程中由人工进行干预和控制的场景。
核心实现方案
1 基于状态的接管控制
<?php
class ManualOverrideManager {
private $processId;
private $redis;
public function __construct($processId) {
$this->processId = $processId;
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
/**
* 设置人工接管状态
*/
public function enableManualOverride($adminId, $reason) {
$overrideData = [
'status' => 'active',
'admin_id' => $adminId,
'reason' => $reason,
'timestamp' => time(),
'expires_at' => time() + 3600 // 默认1小时
];
$this->redis->setex(
"override:{$this->processId}",
3600,
json_encode($overrideData)
);
$this->logOperation($adminId, 'enable_override', $reason);
return true;
}
/**
* 检查是否处于人工接管状态
*/
public function isManualOverrideActive() {
$data = $this->redis->get("override:{$this->processId}");
if (!$data) return false;
$overrideData = json_decode($data, true);
return $overrideData['status'] === 'active';
}
}
2 流程自动化中的检查点
<?php
class AutomatedProcess {
private $overrideManager;
private $pendingActions = [];
public function __construct($processId) {
$this->overrideManager = new ManualOverrideManager($processId);
}
/**
* 在关键步骤前检查人工接管
*/
public function executeStep($stepName, callable $autoFunction) {
// 检查是否被接管
if ($this->overrideManager->isManualOverrideActive()) {
// 保存当前状态等待人工处理
$this->queueForManualReview($stepName);
return ['status' => 'paused', 'message' => '等待人工处理'];
}
// 正常自动执行
try {
$result = $autoFunction();
$this->logAutoExecution($stepName, $result);
return ['status' => 'completed', 'data' => $result];
} catch (Exception $e) {
// 出错时自动请求人工接管
$this->requestManualOverride($stepName, $e->getMessage());
return ['status' => 'error', 'message' => '自动执行失败,请求人工干预'];
}
}
/**
* 将任务加入人工处理队列
*/
private function queueForManualReview($stepName) {
$this->pendingActions[] = [
'step' => $stepName,
'timestamp' => time(),
'status' => 'pending_review'
];
// 存入数据库
DB::table('manual_review_queue')->insert([
'process_id' => $this->processId,
'step_name' => $stepName,
'status' => 'pending',
'created_at' => now()
]);
// 通知管理员
Notification::send($adminUsers, new ManualInterventionRequired($this));
}
}
Web控制台实现
1 接管控制面板API
<?php
// routes/api.php
Route::post('/api/process/{id}/override', 'OverrideController@startOverride');
Route::post('/api/process/{id}/release', 'OverrideController@releaseOverride');
Route::get('/api/process/{id}/status', 'OverrideController@getStatus');
// OverrideController.php
class OverrideController extends Controller {
public function startOverride($processId, Request $request) {
$validated = $request->validate([
'reason' => 'required|string|max:500',
'duration' => 'integer|min:60|max:86400' // 60秒到24小时
]);
$manager = new ManualOverrideManager($processId);
// 检查权限
if (!Auth::user()->can('manual_override')) {
return response()->json(['error' => '无接管权限'], 403);
}
// 检查是否已有接管
if ($manager->isManualOverrideActive()) {
return response()->json(['error' => '当前已有其他管理员接管'], 409);
}
$manager->enableManualOverride(
Auth::id(),
$validated['reason'],
$validated['duration'] ?? 3600
);
// 触发接管事件
event(new ProcessOverridden($processId, Auth::user()));
return response()->json([
'message' => '接管成功',
'override_detail' => [
'admin' => Auth::user()->name,
'start_time' => now(),
'reason' => $validated['reason']
]
]);
}
public function releaseOverride($processId) {
$manager = new ManualOverrideManager($processId);
if (!$manager->isManualOverrideActive()) {
return response()->json(['error' => '当前无接管状态'], 400);
}
$manager->disableManualOverride();
// 恢复自动流程
event(new OverrideReleased($processId));
return response()->json(['message' => '接管已释放']);
}
}
2 前端接管界面
// override-dashboard.js
class ManualOverridePanel {
constructor() {
this.processId = null;
this.ws = null;
this.initWebSocket();
}
initWebSocket() {
this.ws = new WebSocket('wss://your-domain.com/ws/process-override');
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleWebSocketMessage(data);
};
}
handleWebSocketMessage(data) {
switch(data.type) {
case 'override_request':
this.showOverrideRequest(data);
break;
case 'auto_failure':
this.showFailureAlert(data);
break;
case 'status_update':
this.updateStatusDisplay(data);
break;
}
}
startOverride() {
const reason = $('#override-reason').val();
const duration = $('#override-duration').val();
$.ajax({
url: `/api/process/${this.processId}/override`,
method: 'POST',
data: { reason, duration },
success: (response) => {
this.showOverrideMode(response);
this.initializeManualControls();
},
error: (xhr) => {
toastr.error(xhr.responseJSON.error);
}
});
}
initializeManualControls() {
// 激活手动控制面板
$('#manual-controls').removeClass('hidden');
// 加载当前流程状态
this.loadProcessState();
// 初始化流程步骤控制器
this.initStepControls();
}
executeManualStep(stepName, action) {
$.ajax({
url: `/api/process/${this.processId}/manual-step`,
method: 'POST',
data: { step: stepName, action: action },
success: (response) => {
toastr.success(`步骤 ${stepName} 执行成功`);
this.updateProcessTimeline(response.new_state);
}
});
}
}
3 实时监控仪表板
<!-- OverrideMonitor.vue -->
<template>
<div class="override-monitor">
<el-card class="monitor-card">
<div slot="header">
<span>流程监控面板</span>
<el-tag :type="overrideStatus === 'active' ? 'danger' : 'success'">
{{ overrideStatus === 'active' ? '人工接管中' : '自动运行中' }}
</el-tag>
</div>
<!-- 流程时间线 -->
<div class="process-timeline">
<el-timeline>
<el-timeline-item
v-for="(step, index) in processSteps"
:key="index"
:timestamp="step.timestamp"
:type="getTimelineType(step)"
>
{{ step.description }}
</el-timeline-item>
</el-timeline>
</div>
<!-- 手动控制区 -->
<div v-if="isOverriding" class="manual-controls">
<el-form :model="manualForm">
<el-form-item label="选择步骤">
<el-select v-model="manualForm.selectedStep">
<el-option
v-for="step in availableSteps"
:key="step"
:label="step"
:value="step"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="executeStep">
执行步骤
</el-button>
<el-button type="warning" @click="skipStep">
跳过步骤
</el-button>
<el-button type="danger" @click="emergencyStop">
紧急停止
</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
processSteps: [],
overrideStatus: 'inactive',
isOverriding: false,
manualForm: {
selectedStep: ''
}
}
},
methods: {
getTimelineType(step) {
if (step.manual_intervention) return 'warning'
if (step.status === 'completed') return 'success'
if (step.status === 'failed') return 'danger'
return 'primary'
},
async startManualOverride() {
try {
const response = await axios.post(`/api/process/${this.processId}/override`, {
reason: this.overrideReason
})
this.isOverriding = true
this.$message.success('接管成功')
} catch (error) {
this.$message.error('接管失败')
}
}
}
}
</script>
高级实现策略
1 分布式系统中的接管
<?php
class DistributedOverrideManager {
private $lockKey;
private $consul;
public function acquireOverrideLock($processId, $adminId) {
// 使用分布式锁确保唯一接管
$lock = $this->consul->acquireLock(
"override:{$processId}",
$adminId,
60 // 租约时间
);
if (!$lock) {
throw new OverrideConflictException('其他管理员正在接管该流程');
}
// 广播接管事件到所有节点
$this->broadcastOverrideEvent($processId, $adminId, 'acquired');
return true;
}
private function broadcastOverrideEvent($processId, $adminId, $action) {
$message = [
'type' => 'override_event',
'process_id' => $processId,
'admin_id' => $adminId,
'action' => $action,
'timestamp' => time()
];
// 通过消息队列广播
$this->rabbitMQ->publish('process_events', json_encode($message));
}
}
2 接管日志审计
<?php
class OverrideAuditTrail {
public function logOverrideAction($action, $detail) {
AuditLog::create([
'event' => 'manual_override',
'action' => $action,
'admin_id' => Auth::id(),
'process_id' => $this->processId,
'detail' => json_encode($detail),
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'created_at' => now()
]);
}
public function getAuditReport($processId, $startDate, $endDate) {
return AuditLog::where('event', 'manual_override')
->where('process_id', $processId)
->whereBetween('created_at', [$startDate, $endDate])
->orderBy('created_at', 'desc')
->get();
}
}
注意事项
1 安全性考虑
// 权限验证中间件
class OverrideAuthMiddleware {
public function handle($request, $next) {
if (!Auth::user()->hasRole('super_admin') &&
!Auth::user()->hasPermission('manual_override')) {
return response()->json(['error' => '无接管权限'], 403);
}
// 二次确认
if ($request->has('confirmation_code')) {
$this->validateConfirmationCode($request);
}
return $next($request);
}
}
2 优雅降级
// 当接管到期时自动恢复
public function handleOverrideExpiration() {
$this->redis->set('override_expired', true, 60);
// 通知管理员
Notification::route('slack', config('services.slack.override_webhook'))
->notify(new OverrideExpired($this->processId));
// 自动恢复流程
$this->resumeAutomaticProcess();
}
这个实现方案提供了:
- 状态管理 - 使用Redis存储接管状态
- 控制点 - 在自动化流程中设置检查点
- 实时控制 - WebSocket实时通信
- 审计日志 - 完整的操作记录
- 安全性 - 权限控制和二次确认
- 分布式支持 - 分布式锁和事件广播
你可以根据实际需求选择合适的组件进行实现。