AI代码生成工具
This commit is contained in:
@@ -73,6 +73,33 @@ class AdminController extends BaseController
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 个人中心更新资料
|
||||
* @Method POST
|
||||
*/
|
||||
public function updateProfile(): JsonResponse
|
||||
{
|
||||
return jok($this->service->updateProfile(request()->post()), '保存成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 个人中心:登录日志
|
||||
* @Method GET
|
||||
*/
|
||||
public function loginLog(): JsonResponse
|
||||
{
|
||||
return jok($this->service->loginLogList(), '获取成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 个人中心:操作日志
|
||||
* @Method GET
|
||||
*/
|
||||
public function opLog(): JsonResponse
|
||||
{
|
||||
return jok($this->service->opLogList(), '获取成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
* @Method GET
|
||||
|
||||
75
app/Http/Controllers/Api/ApiEndpointController.php
Normal file
75
app/Http/Controllers/Api/ApiEndpointController.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\BaseApp\BaseController;
|
||||
use App\Service\ApiEndpointService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* 接口注册表控制器:仅开放 list / update
|
||||
*/
|
||||
class ApiEndpointController extends BaseController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->service = ApiEndpointService::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页列表
|
||||
* @Method GET
|
||||
*/
|
||||
public function list(): JsonResponse
|
||||
{
|
||||
return jok($this->service->list(), '获取成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新接口说明 / 是否记日志 / 状态
|
||||
* @Method POST
|
||||
*/
|
||||
public function update(): JsonResponse
|
||||
{
|
||||
$params = request()->post();
|
||||
$id = (int) ($params['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
return jerr('参数错误');
|
||||
}
|
||||
unset($params['id']);
|
||||
return jok($this->service->update($id, $params), '更新成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method NO
|
||||
*/
|
||||
public function option(): mixed
|
||||
{
|
||||
return jerr('不支持');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method NO
|
||||
*/
|
||||
public function detail(): JsonResponse
|
||||
{
|
||||
return jerr('不支持');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method NO
|
||||
*/
|
||||
public function create(): JsonResponse
|
||||
{
|
||||
return jerr('不支持');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method NO
|
||||
*/
|
||||
public function delete(): JsonResponse
|
||||
{
|
||||
return jerr('不支持');
|
||||
}
|
||||
}
|
||||
111
app/Http/Controllers/Api/OssConfigController.php
Normal file
111
app/Http/Controllers/Api/OssConfigController.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\BaseApp\BaseController;
|
||||
use App\Service\OssConfigService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* OSS 存储配置控制器:驱动选项 / 启用切换 / 配置 CRUD
|
||||
*/
|
||||
class OssConfigController extends BaseController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->service = OssConfigService::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置列表(卡片,无密钥明文)
|
||||
* @Method GET
|
||||
*/
|
||||
public function list(): JsonResponse
|
||||
{
|
||||
return jok($this->service->listConfigs(), '获取成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method NO
|
||||
*/
|
||||
public function option(): mixed
|
||||
{
|
||||
return jerr('不支持');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Method NO
|
||||
*/
|
||||
public function detail(): JsonResponse
|
||||
{
|
||||
return jerr('不支持');
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增配置(覆盖基类,走加密逻辑)
|
||||
* @Method POST
|
||||
*/
|
||||
public function create(): JsonResponse
|
||||
{
|
||||
return jok($this->service->createConfig(request()->post()), '创建成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新配置
|
||||
* @Method POST
|
||||
*/
|
||||
public function update(): JsonResponse
|
||||
{
|
||||
$params = request()->post();
|
||||
$id = (int) ($params['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
return jerr('参数错误');
|
||||
}
|
||||
unset($params['id']);
|
||||
return jok($this->service->updateConfig($id, $params), '更新成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配置
|
||||
* @Method POST
|
||||
*/
|
||||
public function delete(): JsonResponse
|
||||
{
|
||||
$ids = request()->post('ids');
|
||||
if (empty($ids)) {
|
||||
return jerr('参数错误');
|
||||
}
|
||||
if (!is_array($ids)) {
|
||||
$ids = [$ids];
|
||||
}
|
||||
return jok($this->service->deleteConfigs($ids), '删除成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 驱动枚举选项
|
||||
* @Method GET
|
||||
*/
|
||||
public function driverOptions(): JsonResponse
|
||||
{
|
||||
return jok($this->service->driverOptions(), '获取成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行时选项(卡片 + 当前启用)
|
||||
* @Method GET
|
||||
*/
|
||||
public function runtimeOptions(): JsonResponse
|
||||
{
|
||||
return jok($this->service->getRuntimeOptions(), '获取成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用指定配置
|
||||
* @Method POST
|
||||
*/
|
||||
public function saveRuntime(): JsonResponse
|
||||
{
|
||||
return jok($this->service->saveRuntime(request()->post()), '保存成功');
|
||||
}
|
||||
}
|
||||
156
app/Http/Middleware/ApiOpLogMiddleware.php
Normal file
156
app/Http/Middleware/ApiOpLogMiddleware.php
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\ApiEndpointModel;
|
||||
use App\Models\ApiOpLogModel;
|
||||
use App\Service\common\UserAgentService;
|
||||
use Closure;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* API 操作日志中间件:响应结束后按接口注册表决定是否落库
|
||||
*/
|
||||
class ApiOpLogMiddleware
|
||||
{
|
||||
/**
|
||||
* 透传请求;真正写日志在 terminate,避免拖慢接口响应
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应结束后写操作日志
|
||||
* 匹配:去掉 /api/ 前缀的 url,且 method=0(ANY) 或等于请求方法,is_log=1、status=1
|
||||
*/
|
||||
public function terminate(Request $request, Response $response): void
|
||||
{
|
||||
try {
|
||||
$path = $this->normalizePath($request->path());
|
||||
if ($path === '') {
|
||||
return;
|
||||
}
|
||||
$noInsert = config('nl.log.no_insert', []);
|
||||
if (is_array($noInsert)) {
|
||||
$full = 'api/' . $path;
|
||||
if (in_array($path, $noInsert, true)
|
||||
|| in_array($full, $noInsert, true)
|
||||
|| in_array('/' . $full, $noInsert, true)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$methodCode = $this->mapMethod($request->method());
|
||||
$endpoint = ApiEndpointModel::where('url', $path)
|
||||
->where('deleted_at', 0)
|
||||
->where('status', 1)
|
||||
->where('is_log', 1)
|
||||
->where(function ($q) use ($methodCode) {
|
||||
$q->where('method', 0)->orWhere('method', $methodCode);
|
||||
})
|
||||
->orderByDesc('method')
|
||||
->first();
|
||||
if (!$endpoint) {
|
||||
return;
|
||||
}
|
||||
$userId = $this->resolveUserId($request);
|
||||
$body = $response->getContent();
|
||||
$result = json_decode((string) $body, true);
|
||||
if (!is_array($result)) {
|
||||
$result = ['raw' => mb_substr((string) $body, 0, 2000)];
|
||||
}
|
||||
$code = $result['code'] ?? null;
|
||||
$type = ((int) $code === 0) ? 0 : 1;
|
||||
$ua = UserAgentService::getInstance();
|
||||
ApiOpLogModel::insert([
|
||||
'user_id' => $userId,
|
||||
'url' => $path,
|
||||
'method' => $methodCode,
|
||||
'controller' => (string) ($endpoint->controller ?? ''),
|
||||
'ip' => (string) get_ip(),
|
||||
'param' => json_encode($this->collectParams($request), JSON_UNESCAPED_UNICODE),
|
||||
'result' => json_encode($result, JSON_UNESCAPED_UNICODE),
|
||||
'type' => $type,
|
||||
'result_code' => (string) ($code ?? ''),
|
||||
'platform_type' => 0,
|
||||
'belong_id' => 0,
|
||||
'user_type' => 0,
|
||||
'equipment' => $ua->parseEquipment(),
|
||||
'browser' => $ua->parseBrowser(),
|
||||
'created_at' => time(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
// 日志失败不影响主流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化路径:去掉 api/ 前缀
|
||||
*/
|
||||
private function normalizePath(string $path): string
|
||||
{
|
||||
$path = trim($path, '/');
|
||||
if (str_starts_with($path, 'api/')) {
|
||||
$path = substr($path, 4);
|
||||
}
|
||||
return trim($path, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP 方法映射:GET=1 POST=2 其他=0
|
||||
*/
|
||||
private function mapMethod(string $method): int
|
||||
{
|
||||
return match (strtoupper($method)) {
|
||||
'GET' => 1,
|
||||
'POST' => 2,
|
||||
default => 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Bearer JWT 解析 user_id;失败返回 0(不抛鉴权异常)
|
||||
*/
|
||||
private function resolveUserId(Request $request): int
|
||||
{
|
||||
try {
|
||||
$token = $request->bearerToken();
|
||||
if (empty($token)) {
|
||||
return 0;
|
||||
}
|
||||
$secret = (string) config('nl.jwt.secret', '');
|
||||
if (strlen($secret) < 32) {
|
||||
$secret = hash('sha256', $secret !== '' ? $secret : 'nl_admin_jwt_fallback_secret');
|
||||
}
|
||||
$decoded = JWT::decode($token, new Key($secret, 'HS256'));
|
||||
return (int) ($decoded->data->id ?? 0);
|
||||
} catch (\Throwable $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集请求参数并脱敏密码类字段
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function collectParams(Request $request): array
|
||||
{
|
||||
$all = array_merge($request->query(), $request->request->all());
|
||||
$maskKeys = [
|
||||
'password', 'old_password', 'new_password', 'confirm_password',
|
||||
'access_key', 'secret_key', 'api_key', 'token',
|
||||
];
|
||||
foreach ($maskKeys as $k) {
|
||||
if (array_key_exists($k, $all) && $all[$k] !== '' && $all[$k] !== null) {
|
||||
$all[$k] = '******';
|
||||
}
|
||||
}
|
||||
return $all;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user