feat: 发布智能体版

This commit is contained in:
augushong
2026-03-26 20:22:34 +08:00
parent 7ee9e102a5
commit 8cc08bcb8c
138 changed files with 7964 additions and 660 deletions

View File

@@ -0,0 +1,326 @@
<?php
namespace base\common\service;
use Exception;
use Throwable;
abstract class ErrorHandlerBase
{
/**
* 错误码注册表
*/
protected array $errorCodes = [
// 通用错误 (ERR_GEN_XXX)
'ERR_GEN_UNKNOWN' => '未知错误',
'ERR_GEN_INVALID_PARAM' => '参数错误',
'ERR_GEN_MISSING_PARAM' => '缺少必需参数',
'ERR_GEN_OPERATION_FAILED' => '操作失败',
'ERR_GEN_PERMISSION_DENIED' => '权限不足',
'ERR_GEN_NOT_FOUND' => '资源不存在',
'ERR_GEN_TIMEOUT' => '操作超时',
// 数据库错误 (ERR_DB_XXX)
'ERR_DB_CONNECTION' => '数据库连接失败',
'ERR_DB_QUERY' => '数据库查询失败',
'ERR_DB_INSERT' => '数据插入失败',
'ERR_DB_UPDATE' => '数据更新失败',
'ERR_DB_DELETE' => '数据删除失败',
'ERR_DB_TRANSACTION' => '数据库事务执行失败',
'ERR_DB_SCHEME_MISMATCH' => '数据库结构与期望不符',
// 文件系统错误 (ERR_FS_XXX)
'ERR_FS_NOT_FOUND' => '文件不存在',
'ERR_FS_READ_FAILED' => '文件读取失败',
'ERR_FS_WRITE_FAILED' => '文件写入失败',
'ERR_FS_DELETE_FAILED' => '文件删除失败',
'ERR_FS_PERMISSION' => '文件权限不足',
// 网络错误 (ERR_NET_XXX)
'ERR_NET_CONNECTION' => '网络连接失败',
'ERR_NET_TIMEOUT' => '网络请求超时',
'ERR_NET_RESPONSE' => '网络响应错误',
// 配置错误 (ERR_CFG_XXX)
'ERR_CFG_MISSING' => '配置缺失',
'ERR_CFG_INVALID' => '配置无效',
];
/**
* 修复建议注册表
*/
protected array $suggestions = [
// 通用错误修复建议
'ERR_GEN_UNKNOWN' => '未知错误,请稍后重试或联系管理员',
'ERR_GEN_INVALID_PARAM' => '请检查传入的参数是否符合要求',
'ERR_GEN_MISSING_PARAM' => '请确保所有必需参数都已提供',
'ERR_GEN_OPERATION_FAILED' => '请稍后重试,如果问题持续存在请联系管理员',
'ERR_GEN_PERMISSION_DENIED' => '请检查您是否有执行此操作的权限',
'ERR_GEN_NOT_FOUND' => '请确认请求的资源ID是否正确',
'ERR_GEN_TIMEOUT' => '请检查网络连接或稍后重试',
// 数据库错误修复建议
'ERR_DB_CONNECTION' => '请检查数据库连接配置和网络连接',
'ERR_DB_QUERY' => '请检查SQL语句语法和数据库表结构',
'ERR_DB_INSERT' => '请检查数据是否符合表结构和约束条件',
'ERR_DB_UPDATE' => '请确保要更新的数据存在且符合约束条件',
'ERR_DB_DELETE' => '请确保要删除的数据存在',
'ERR_DB_TRANSACTION' => '请检查事务中的操作是否都执行成功',
'ERR_DB_SCHEME_MISMATCH' => '请运行数据库迁移命令: php think migrate:run',
// 文件系统错误修复建议
'ERR_FS_NOT_FOUND' => '请检查文件路径是否正确',
'ERR_FS_READ_FAILED' => '请检查文件是否存在且有读取权限',
'ERR_FS_WRITE_FAILED' => '请检查目录是否存在且有写入权限',
'ERR_FS_DELETE_FAILED' => '请检查文件是否存在且有删除权限',
'ERR_FS_PERMISSION' => '请检查文件或目录的权限设置',
// 网络错误修复建议
'ERR_NET_CONNECTION' => '请检查网络连接和目标服务器状态',
'ERR_NET_TIMEOUT' => '请检查网络连接或增加超时时间',
'ERR_NET_RESPONSE' => '请检查请求参数和服务器响应',
// 配置错误修复建议
'ERR_CFG_MISSING' => '请在配置文件中添加缺失的配置项',
'ERR_CFG_INVALID' => '请检查配置项的值是否符合要求',
];
/**
* 获取结构化错误信息
*
* @param string $errorCode 错误码
* @param string|null $errorMessage 错误消息(覆盖默认错误消息)
* @param array $context 上下文信息
* @return array 结构化错误信息
*/
public function getError(string $errorCode, ?string $errorMessage = null, array $context = []): array
{
$defaultMessage = $this->errorCodes[$errorCode] ?? $this->errorCodes['ERR_GEN_UNKNOWN'];
$actualMessage = $errorMessage ?? $defaultMessage;
$error = [
'success' => false,
'error_code' => $errorCode,
'error_message' => $actualMessage,
];
// 添加文件和行信息(如果存在)
if (isset($context['file'])) {
$error['file'] = $context['file'];
}
if (isset($context['line'])) {
$error['line'] = $context['line'];
}
// 添加修复建议
$suggestion = $this->suggestions[$errorCode] ?? $this->suggestions['ERR_GEN_UNKNOWN'];
$error['suggestion'] = $suggestion;
// 添加额外的上下文信息
if (!empty($context)) {
$error['context'] = $context;
}
return $error;
}
/**
* 从异常生成结构化错误信息
*
* @param Throwable $exception 异常对象
* @param string|null $customErrorCode 自定义错误码
* @return array 结构化错误信息
*/
public function getErrorForException(Throwable $exception, ?string $customErrorCode = null): array
{
// 尝试从异常消息推断错误码
$errorCode = $customErrorCode ?? $this->inferErrorCodeFromException($exception);
$error = [
'success' => false,
'error_code' => $errorCode,
'error_message' => $exception->getMessage(),
];
// 添加文件和行信息
if ($exception->getFile()) {
$error['file'] = $exception->getFile();
}
if ($exception->getLine()) {
$error['line'] = $exception->getLine();
}
// 添加修复建议
$suggestion = $this->suggestions[$errorCode] ?? $this->suggestions['ERR_GEN_UNKNOWN'];
$error['suggestion'] = $suggestion;
// 添加异常类型
$error['exception_type'] = get_class($exception);
// 添加堆栈跟踪(在开发模式下)
if ($this->isDebugMode()) {
$error['trace'] = $this->formatTrace($exception);
}
return $error;
}
/**
* 从异常推断错误码
*
* @param Throwable $exception 异常对象
* @return string 错误码
*/
protected function inferErrorCodeFromException(Throwable $exception): string
{
$message = $exception->getMessage();
$class = get_class($exception);
// 根据异常类型推断
if (strpos($class, 'Db') !== false || strpos($class, 'Query') !== false) {
if (strpos($message, 'connection') !== false || strpos($message, 'connect') !== false) {
return 'ERR_DB_CONNECTION';
}
if (strpos($message, 'SQLSTATE') !== false) {
return 'ERR_DB_QUERY';
}
return 'ERR_DB_OPERATION_FAILED';
}
if (strpos($class, 'File') !== false || strpos($class, 'Stream') !== false) {
if (strpos($message, 'No such file') !== false || strpos($message, 'not found') !== false) {
return 'ERR_FS_NOT_FOUND';
}
if (strpos($message, 'permission') !== false) {
return 'ERR_FS_PERMISSION';
}
return 'ERR_FS_READ_FAILED';
}
if (strpos($class, 'Network') !== false || strpos($class, 'Curl') !== false) {
if (strpos($message, 'timeout') !== false) {
return 'ERR_NET_TIMEOUT';
}
return 'ERR_NET_CONNECTION';
}
// 根据消息内容推断
if (strpos($message, 'permission') !== false || strpos($message, 'denied') !== false) {
return 'ERR_GEN_PERMISSION_DENIED';
}
if (strpos($message, 'not found') !== false || strpos($message, '不存在') !== false) {
return 'ERR_GEN_NOT_FOUND';
}
if (strpos($message, 'timeout') !== false) {
return 'ERR_GEN_TIMEOUT';
}
return 'ERR_GEN_UNKNOWN';
}
/**
* 格式化堆栈跟踪
*
* @param Throwable $exception 异常对象
* @return array 格式化的堆栈跟踪
*/
protected function formatTrace(Throwable $exception): array
{
$trace = [];
foreach ($exception->getTrace() as $index => $frame) {
$traceItem = [
'index' => $index,
];
if (isset($frame['file'])) {
$traceItem['file'] = $frame['file'];
}
if (isset($frame['line'])) {
$traceItem['line'] = $frame['line'];
}
if (isset($frame['function'])) {
$traceItem['function'] = $frame['function'];
}
if (isset($frame['class'])) {
$traceItem['class'] = $frame['class'];
}
if (isset($frame['type'])) {
$traceItem['type'] = $frame['type'];
}
$trace[] = $traceItem;
}
return $trace;
}
/**
* 检查是否为调试模式
*
* @return bool
*/
protected function isDebugMode(): bool
{
try {
$app = \think\facade\App::instance();
return (bool)($app->config->get('app.app_debug') ?? false);
} catch (\Exception $e) {
return false;
}
}
/**
* 输出错误作为JSON
*
* @param array $error 错误信息
* @return string JSON格式的错误信息
*/
public function outputError(array $error): string
{
$options = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
return json_encode($error, $options);
}
/**
* 注册自定义错误码
*
* @param string $errorCode 错误码
* @param string $errorMessage 错误消息
* @param string|null $suggestion 修复建议
* @return void
*/
public function registerErrorCode(string $errorCode, string $errorMessage, ?string $suggestion = null): void
{
$this->errorCodes[$errorCode] = $errorMessage;
if ($suggestion !== null) {
$this->suggestions[$errorCode] = $suggestion;
}
}
/**
* 批量注册错误码
*
* @param array $errors 错误码数组,格式:['ERR_XXX' => ['message' => '...', 'suggestion' => '...']]
* @return void
*/
public function registerErrorCodes(array $errors): void
{
foreach ($errors as $errorCode => $config) {
$this->errorCodes[$errorCode] = $config['message'] ?? '未知错误';
if (isset($config['suggestion'])) {
$this->suggestions[$errorCode] = $config['suggestion'];
}
}
}
/**
* 获取所有已注册的错误码
*
* @return array 错误码数组
*/
public function getRegisteredErrorCodes(): array
{
return $this->errorCodes;
}
}