This commit is contained in:
83
app/Job/BaseJob.php
Normal file
83
app/Job/BaseJob.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Author: ykxiao
|
||||
* Date: 2025/6/3
|
||||
* Time: 下午10:55
|
||||
* Description:
|
||||
*
|
||||
* (c) ykxiao <yk_9001@hotmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Job;
|
||||
|
||||
use App\Context\QueueContext;
|
||||
use App\Log\Log;
|
||||
use Exception;
|
||||
use Hyperf\AsyncQueue\Job;
|
||||
use Hyperf\DbConnection\Db;
|
||||
|
||||
/**
|
||||
* Author: ykxiao
|
||||
* Date: 2025/6/3
|
||||
* Time: 下午10:57
|
||||
* Description: Job基础任务类.
|
||||
*
|
||||
* (c) ykxiao <yk_9001@hotmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
abstract class BaseJob extends Job
|
||||
{
|
||||
public function __construct(public array $data)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
// 设置用户信息上下文信息
|
||||
if (!empty($user = $this->data['user'])) {
|
||||
QueueContext::setUser($user);
|
||||
}
|
||||
|
||||
if (!empty($company = $this->data['company'])) {
|
||||
QueueContext::setCompanyInfo($company);
|
||||
}
|
||||
|
||||
// 运行业务逻辑, 总是在事务中执行,保证事务的原子性
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
$this->process();
|
||||
|
||||
Db::commit();
|
||||
} catch (Exception $e) {
|
||||
Db::rollBack();
|
||||
$this->logError($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 子类必须实现的业务逻辑处理方法
|
||||
*/
|
||||
abstract protected function process(): void;
|
||||
|
||||
/**
|
||||
* 日志记录,可按需扩展日志通道
|
||||
*/
|
||||
protected function logError(Exception $e): void
|
||||
{
|
||||
Log::get('queue', 'queue')->error(sprintf(
|
||||
"[%s] %s in %s:%d\n%s",
|
||||
static::class,
|
||||
$e->getMessage(),
|
||||
$e->getFile(),
|
||||
$e->getLine(),
|
||||
$e->getTraceAsString()
|
||||
));
|
||||
}
|
||||
}
|
141
app/Job/ColumnConfigJob.php
Executable file
141
app/Job/ColumnConfigJob.php
Executable file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace App\Job;
|
||||
|
||||
use App\Model\ColumnConfig;
|
||||
use App\Scope\CompanyScope;
|
||||
|
||||
use Hyperf\Coroutine\Parallel;
|
||||
use function Hyperf\Collection\collect;
|
||||
use function Hyperf\Config\config;
|
||||
|
||||
class ColumnConfigJob extends BaseJob
|
||||
{
|
||||
protected function process(): void
|
||||
{
|
||||
['user' => $user, 'method' => $method, 'params' => $params] = $this->data;
|
||||
|
||||
// 提交了保存列配置
|
||||
if (!isset($params['save_column'])) return;
|
||||
if ($params['save_column'] === false) {
|
||||
$this->deleteColumnConfig($user, $method);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取默认配置, 没有配置则不处理
|
||||
$configList = config('column_config.' . $method) ?? [];
|
||||
if (empty($configList)) return;
|
||||
|
||||
$submitConfig = $params['column_config'];
|
||||
$submittedMap = collect($submitConfig)->keyBy('prop')->toArray();
|
||||
|
||||
$parallel = new Parallel();
|
||||
|
||||
foreach ($configList as $key => $value) {
|
||||
$parallel->add(function () use ($key, $value, $submittedMap, $user) {
|
||||
$value['sort'] = $key + 1;
|
||||
|
||||
// 存在前端提交的列
|
||||
if (isset($submittedMap[$value['prop']])) {
|
||||
$merged = array_merge([
|
||||
'condition' => 'like',
|
||||
'search_type' => 'text',
|
||||
'is_search' => 1,
|
||||
'sortable' => 0,
|
||||
], $value, $submittedMap[$value['prop']]);
|
||||
|
||||
return $this->prepareConfig($merged, $user);
|
||||
}
|
||||
|
||||
// 否则删除该列配置
|
||||
ColumnConfig::query()->withoutGlobalScope(CompanyScope::class)
|
||||
->where([
|
||||
'prop' => $value['prop'],
|
||||
'method' => $this->data['method'],
|
||||
'creator_id' => $user['id'],
|
||||
])
|
||||
->forceDelete();
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
// 执行并获取所有结果
|
||||
$results = $parallel->wait();
|
||||
|
||||
// 过滤非 null 的更新数据
|
||||
$updates = array_filter($results);
|
||||
|
||||
if (!empty($updates)) {
|
||||
$this->updateOrCreateColumnConfigs($updates, $method, $user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新或创建列配置.
|
||||
*/
|
||||
private function updateOrCreateColumnConfigs(array $configs, string $method, array $creator): void
|
||||
{
|
||||
// 默认配置key值
|
||||
$defaultKeys = (new ColumnConfig())->getFillable();
|
||||
|
||||
// 删除$configs里不存在$defaultKeys里的字段,防止前端传递的额外字段导致更新失败
|
||||
$configs = array_map(function ($config) use ($defaultKeys) {
|
||||
$newConfig = array_intersect_key($config, array_flip($defaultKeys));
|
||||
$newConfig['sort'] = $config['sort'] ?? 0;
|
||||
return $newConfig;
|
||||
}, $configs);
|
||||
|
||||
// 添加公共字段
|
||||
foreach ($configs as &$config) {
|
||||
$config['company_id'] = $creator['company_id'] ?? 0;
|
||||
$config['method'] = $method;
|
||||
$config['creator_id'] = $creator['id'];
|
||||
$config['creator_name'] = $creator['name'];
|
||||
$config['created_at'] = $config['updated_at'] = time();
|
||||
}
|
||||
unset($config);
|
||||
|
||||
$updateKeys = array_keys($configs[0]);
|
||||
// 删除不需要更新的字段
|
||||
unset(
|
||||
$updateKeys[array_search('creator_name', $updateKeys, true)],
|
||||
$updateKeys[array_search('prop', $updateKeys, true)],
|
||||
$updateKeys[array_search('method', $updateKeys, true)],
|
||||
$updateKeys[array_search('creator_id', $updateKeys, true)],
|
||||
);
|
||||
|
||||
// 批量插入或更新
|
||||
ColumnConfig::query()->withoutGlobalScope(CompanyScope::class)
|
||||
->upsert($configs, ['prop', 'method', 'creator_id'], array_values($updateKeys));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除列配置.
|
||||
*/
|
||||
private function deleteColumnConfig(array $user, string $method): void
|
||||
{
|
||||
ColumnConfig::query()->withoutGlobalScope(CompanyScope::class)
|
||||
->where(['method' => $method, 'creator_id' => $user['id']])
|
||||
->forceDelete();
|
||||
}
|
||||
|
||||
private function prepareConfig(array $config, array $user): array
|
||||
{
|
||||
return array_merge($config, [
|
||||
'company_id' => $user['company_id'] ?? 0,
|
||||
'creator_id' => $user['id'],
|
||||
'creator_name' => $user['name'],
|
||||
]);
|
||||
}
|
||||
}
|
87
app/Job/OpLogsJob.php
Executable file
87
app/Job/OpLogsJob.php
Executable file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Job;
|
||||
|
||||
use App\Constants\SourceConst;
|
||||
use App\JsonRpc\EasyAppServiceInterface;
|
||||
use App\Model\OperatorLogs;
|
||||
use Exception;
|
||||
use Hyperf\Collection\Collection;
|
||||
use function Hyperf\Collection\collect;
|
||||
use function Hyperf\Config\config;
|
||||
use function Hyperf\Support\make;
|
||||
|
||||
/**
|
||||
* Author: ykxiao
|
||||
* Date: 2024/12/25
|
||||
* Time: 上午9:36
|
||||
* Description: 操作日志记录任务.
|
||||
*
|
||||
* (c) ykxiao <yk_9001@hotmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
class OpLogsJob extends BaseJob
|
||||
{
|
||||
/**
|
||||
* 处理日志记录逻辑。
|
||||
* 该方法首先尝试获取日志操作信息,如果信息不为空,则根据这些信息填充操作日志数组,
|
||||
* 包括日志类型、标题、计时器以及来源信息。随后,它将尝试获取当前用户信息,并最后创建操作日志记录。
|
||||
*
|
||||
* @return void 该方法没有返回值。
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function process(): void
|
||||
{
|
||||
// 尝试获取日志操作信息
|
||||
$logAction = $this->getLogAction();
|
||||
// 如果日志操作信息为空,则直接返回,不进行后续操作
|
||||
if ($logAction->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rpcResult = make(EasyAppServiceInterface::class)->getClientIPInfo(['ip' => $this->data['ip']]);
|
||||
|
||||
// 构建请求日志消息
|
||||
$clientIPInfo = $rpcResult['result']['ip_info'] ?? '';
|
||||
|
||||
// 从日志操作信息中提取日志类型,并保存到操作日志数组中
|
||||
$type = $logAction->first()['id'] ?? 0;
|
||||
$this->data['type'] = $type;
|
||||
// 同样从日志操作信息中提取日志标题,并保存
|
||||
$this->data['log_title'] = $logAction->first()['name'] ?? '';
|
||||
// 初始化计时器
|
||||
$this->data['timer'] = 0;
|
||||
// 设置日志来源,优先使用已存在的来源信息,如果不存在,则尝试从路由前缀获取来源信息
|
||||
$this->data['source'] = $this->data['source'] ?: $this->getRoutePrefix();
|
||||
// 查询IP属地,并保存到操作日志数组中
|
||||
$this->data['location'] = $clientIPInfo;
|
||||
|
||||
// 创建操作日志记录
|
||||
OperatorLogs::query()->create($this->data);
|
||||
}
|
||||
|
||||
|
||||
private function getLogAction(): Collection
|
||||
{
|
||||
$defineLogs = config('op_logs');
|
||||
return collect($defineLogs)->where('action', '=', $this->data['action']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由前缀.
|
||||
*/
|
||||
private function getRoutePrefix(): int
|
||||
{
|
||||
$arr = explode('/', $this->data['route']);
|
||||
$res = $arr[0] ?? '';
|
||||
return match ($res) {
|
||||
'api' => SourceConst::SOURCE_PC,
|
||||
'mobile' => SourceConst::SOURCE_MOBILE,
|
||||
default => 0,
|
||||
};
|
||||
}
|
||||
}
|
54
app/Job/RequestWriteLogsJob.php
Normal file
54
app/Job/RequestWriteLogsJob.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Job;
|
||||
|
||||
use App\JsonRpc\EasyAppServiceInterface;
|
||||
use App\Log\Log;
|
||||
use function Hyperf\Support\make;
|
||||
|
||||
/**
|
||||
* Author: ykxiao
|
||||
* Date: 2025/6/4
|
||||
* Time: 上午10:23
|
||||
* Description: 请求日志写入任务.
|
||||
*
|
||||
* (c) ykxiao <yk_9001@hotmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
class RequestWriteLogsJob extends BaseJob
|
||||
{
|
||||
protected function process(): void
|
||||
{
|
||||
$params = $this->data['params']; // 提取请求参数
|
||||
|
||||
// 从参数中删除敏感信息
|
||||
foreach ($params as $key => $value) {
|
||||
if (in_array($key, ['password', 'pwd', 'pwd_conf', 'original_pwd'])) {
|
||||
unset($params[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$rpcResult = make(EasyAppServiceInterface::class)->getClientIPInfo([
|
||||
'ip' => $this->data['client_ip']
|
||||
]);
|
||||
|
||||
$clientIPInfo = $rpcResult['result']['ip_info'] ?? '';
|
||||
|
||||
$logMessage = sprintf('%s %s %s',
|
||||
$this->data['client_ip'] . ' ' . $clientIPInfo,
|
||||
$this->data['method'],
|
||||
$this->data['uri']
|
||||
);
|
||||
if (!empty($params)) {
|
||||
$logMessage .= ' params: ' . json_encode($params, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
$log = Log::get('request', 'request');
|
||||
$log->info($logMessage);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user