service = $service; } /** * 设置操作上下文 * @param array $context 上下文信息 */ public function setContext($context) { $this->context = array_merge($this->context, $context); } /** * 获取操作上下文 * @return array */ public function getContext() { return $this->context; } /** * 魔术方法,代理所有方法调用 * @param string $method 方法名 * @param array $args 参数 * @return mixed */ public function __call($method, $args) { // 前置处理 $this->beforeAction($method, $args); try { // 调用原始方法 $result = call_user_func_array([$this->service, $method], $args); // 后置处理 $this->afterAction($method, $args, $result); return $result; } catch (Exception $e) { // 异常处理 $this->onException($method, $args, $e); throw $e; } } /** * 前置处理 * @param string $method 方法名 * @param array $args 参数 */ protected function beforeAction($method, $args) { // 记录方法调用开始 $this->context['method'] = $method; $this->context['args'] = $args; $this->context['start_time'] = microtime(true); $this->context['start_memory'] = memory_get_usage(); } /** * 后置处理 * @param string $method 方法名 * @param array $args 参数 * @param mixed $result 结果 */ protected function afterAction($method, $args, $result) { // 记录方法调用结束 $this->context['end_time'] = microtime(true); $this->context['end_memory'] = memory_get_usage(); $this->context['execution_time'] = $this->context['end_time'] - $this->context['start_time']; $this->context['memory_usage'] = $this->context['end_memory'] - $this->context['start_memory']; $this->context['result'] = $result; // 根据方法名自动记录操作 $this->autoRecordAction($method, $args, $result); } /** * 异常处理 * @param string $method 方法名 * @param array $args 参数 * @param Exception $e 异常对象 */ protected function onException($method, $args, $e) { // 记录异常 $this->context['exception'] = $e->getMessage(); $this->context['exception_code'] = $e->getCode(); $this->context['exception_trace'] = $e->getTraceAsString(); // 可以在这里记录异常日志 \think\Log::error('订单操作异常: ' . $e->getMessage(), [ 'method' => $method, 'args' => $args, 'context' => $this->context ]); } /** * 自动记录操作 * @param string $method 方法名 * @param array $args 参数 * @param mixed $result 结果 */ protected function autoRecordAction($method, $args, $result) { // 方法名到操作类型的映射 $methodActionMap = [ 'create' => OrderActionEnum::ACTION_CREATE, 'pay' => OrderActionEnum::ACTION_PAY, 'ship' => OrderActionEnum::ACTION_SHIP, 'receive' => OrderActionEnum::ACTION_RECEIVE, 'cancel' => OrderActionEnum::ACTION_CANCEL, 'refund' => OrderActionEnum::ACTION_REFUND, 'return' => OrderActionEnum::ACTION_RETURN, 'complete' => OrderActionEnum::ACTION_COMPLETE, 'comment' => OrderActionEnum::ACTION_COMMENT, 'modify' => OrderActionEnum::ACTION_MODIFY, 'remind' => OrderActionEnum::ACTION_REMIND, ]; // 查找匹配的操作类型 $actionType = null; foreach ($methodActionMap as $keyword => $action) { if (stripos($method, $keyword) !== false) { $actionType = $action; break; } } if (!$actionType) { return; // 没有匹配的操作类型,不记录 } // 尝试从参数中提取订单编号 $orderSn = $this->extractOrderSn($args); if (!$orderSn) { return; // 没有订单编号,不记录 } // 获取操作者信息 $operator = $this->context['operator'] ?? 'unknown'; $userType = $this->context['user_type'] ?? OrderActionEnum::USER_TYPE_ADMIN; $userId = $this->context['user_id'] ?? 0; // 构建备注信息 $memo = $this->buildMemo($method, $args, $result); // 构建额外数据 $extra = [ 'method' => $method, 'execution_time' => $this->context['execution_time'], 'memory_usage' => $this->context['memory_usage'], 'user_agent' => request()->server('HTTP_USER_AGENT', ''), 'ip' => request()->ip(), ]; // 记录操作 try { switch ($userType) { case OrderActionEnum::USER_TYPE_CUSTOMER: OrderActionService::recordUserAction($orderSn, $actionType, $operator, $memo, $userId, $extra); break; case OrderActionEnum::USER_TYPE_ADMIN: OrderActionService::recordAdminAction($orderSn, $actionType, $operator, $memo, $userId, $extra); break; case OrderActionEnum::USER_TYPE_SYSTEM: OrderActionService::recordSystemAction($orderSn, $actionType, $memo, $extra); break; } } catch (Exception $e) { // 记录操作失败不应该影响主流程 \think\Log::error('自动记录订单操作失败: ' . $e->getMessage()); } } /** * 从参数中提取订单编号 * @param array $args 参数数组 * @return string|null */ protected function extractOrderSn($args) { // 尝试从不同位置提取订单编号 foreach ($args as $arg) { if (is_string($arg) && preg_match('/^[A-Z0-9]{10,}$/', $arg)) { return $arg; // 假设订单编号是10位以上的大写字母和数字组合 } if (is_array($arg) && isset($arg['order_sn'])) { return $arg['order_sn']; } if (is_array($arg) && isset($arg['out_trade_no'])) { return $arg['out_trade_no']; } if (is_object($arg) && property_exists($arg, 'order_sn')) { return $arg->order_sn; } } return null; } /** * 构建备注信息 * @param string $method 方法名 * @param array $args 参数 * @param mixed $result 结果 * @return string */ protected function buildMemo($method, $args, $result) { $memo = "执行方法: {$method}"; // 添加执行时间信息 if (isset($this->context['execution_time'])) { $memo .= sprintf(", 耗时: %.3fs", $this->context['execution_time']); } // 添加内存使用信息 if (isset($this->context['memory_usage'])) { $memo .= sprintf(", 内存: %s", $this->formatBytes($this->context['memory_usage'])); } // 添加自定义备注 if (isset($this->context['memo'])) { $memo .= ", " . $this->context['memo']; } return $memo; } /** * 格式化字节数 * @param int $bytes 字节数 * @return string */ protected function formatBytes($bytes) { if ($bytes >= 1024 * 1024) { return sprintf('%.2fMB', $bytes / (1024 * 1024)); } elseif ($bytes >= 1024) { return sprintf('%.2fKB', $bytes / 1024); } else { return $bytes . 'B'; } } /** * 创建装饰器实例 * @param object $service 被装饰的服务对象 * @param array $context 上下文信息 * @return OrderActionDecorator */ public static function create($service, $context = []) { $decorator = new static($service); $decorator->setContext($context); return $decorator; } /** * 装饰服务方法的静态工厂方法 * @param object $service 被装饰的服务对象 * @param string $operator 操作者 * @param string $userType 用户类型 * @param int $userId 用户ID * @param array $extra 额外上下文 * @return OrderActionDecorator */ public static function decorate($service, $operator, $userType = OrderActionEnum::USER_TYPE_ADMIN, $userId = 0, $extra = []) { $context = array_merge([ 'operator' => $operator, 'user_type' => $userType, 'user_id' => $userId, ], $extra); return self::create($service, $context); } /** * 为用户操作创建装饰器 * @param object $service 被装饰的服务对象 * @param string $operator 操作者 * @param int $userId 用户ID * @param array $extra 额外上下文 * @return OrderActionDecorator */ public static function forUser($service, $operator, $userId = 0, $extra = []) { return self::decorate($service, $operator, OrderActionEnum::USER_TYPE_CUSTOMER, $userId, $extra); } /** * 为管理员操作创建装饰器 * @param object $service 被装饰的服务对象 * @param string $operator 操作者 * @param int $adminId 管理员ID * @param array $extra 额外上下文 * @return OrderActionDecorator */ public static function forAdmin($service, $operator, $adminId = 0, $extra = []) { return self::decorate($service, $operator, OrderActionEnum::USER_TYPE_ADMIN, $adminId, $extra); } /** * 为系统操作创建装饰器 * @param object $service 被装饰的服务对象 * @param array $extra 额外上下文 * @return OrderActionDecorator */ public static function forSystem($service, $extra = []) { return self::decorate($service, 'system', OrderActionEnum::USER_TYPE_SYSTEM, 0, $extra); } }