同步
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ SuperAdmin/.specstory/
|
||||
Cunkebao/dist
|
||||
Touchkebao/.specstory/
|
||||
Serverruntime/
|
||||
Moncter/提示词/
|
||||
|
||||
24
Moncter/.env.example
Normal file
24
Moncter/.env.example
Normal file
@@ -0,0 +1,24 @@
|
||||
# 存客宝标签系统 - 环境变量配置示例
|
||||
# 复制此文件为 .env 并修改相应的配置值,不要提交到版本控制系统
|
||||
|
||||
# ============================================
|
||||
# 加密配置
|
||||
# ============================================
|
||||
|
||||
# AES 加密密钥(至少32字符,建议使用随机生成的强密钥)
|
||||
# 生产环境请务必修改此密钥,并妥善保管
|
||||
ENCRYPTION_AES_KEY=your-32-byte-secret-key-here-12345678
|
||||
|
||||
# 哈希盐值(用于身份证哈希,增强安全性)
|
||||
# 生产环境请务必修改此盐值
|
||||
ENCRYPTION_HASH_SALT=your-hash-salt-here-change-in-production
|
||||
|
||||
# ============================================
|
||||
# 应用配置
|
||||
# ============================================
|
||||
|
||||
# 应用环境(development/production)
|
||||
APP_ENV=development
|
||||
|
||||
# 应用调试模式(true/false)
|
||||
APP_DEBUG=true
|
||||
@@ -1,11 +1,26 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"MongoDB": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "mongodb-mcp-server@latest", "--readOnly"],
|
||||
"env": {
|
||||
"MDB_MCP_CONNECTION_STRING": "mongodb://ckb:123456@192.168.1.106:27017/ckb"
|
||||
}
|
||||
"mcpServers": {
|
||||
"MongoDB_ckb": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "mongodb-mcp-server@1.2.0", "--readOnly"],
|
||||
"env": {
|
||||
"MDB_MCP_CONNECTION_STRING": "mongodb://ckb:123456@192.168.1.106:27017/ckb"
|
||||
}
|
||||
},
|
||||
"MongoDB_KR": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "mongodb-mcp-server@1.2.0", "--readOnly"],
|
||||
"env": {
|
||||
"MDB_MCP_CONNECTION_STRING": "mongodb://admin:key123456@192.168.2.16:27017/admin"
|
||||
}
|
||||
},
|
||||
"Moncter": {
|
||||
"command": "node",
|
||||
"args": ["./MCP/moncter-mcp-server/dist/index.js"],
|
||||
"cwd": "E:/Cunkebao/Cunkebao02/Moncter",
|
||||
"env": {
|
||||
"MONCTER_API_URL": "http://127.0.0.1:8787"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Moncter/TaskShow/v0.39.1.tar.gz
Normal file
BIN
Moncter/TaskShow/v0.39.1.tar.gz
Normal file
Binary file not shown.
@@ -21,4 +21,134 @@ class IndexController
|
||||
return json(['code' => 0, 'msg' => 'ok']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 MongoDB 数据库连接
|
||||
* GET /api/test/db
|
||||
*/
|
||||
public function testDb(Request $request)
|
||||
{
|
||||
$result = [
|
||||
'code' => 0,
|
||||
'msg' => 'ok',
|
||||
'data' => [
|
||||
'config' => [],
|
||||
'connection' => [],
|
||||
'test_query' => [],
|
||||
],
|
||||
];
|
||||
|
||||
try {
|
||||
// 读取数据库配置
|
||||
$dbConfig = config('database', []);
|
||||
$mongoConfig = $dbConfig['connections']['mongodb'] ?? null;
|
||||
|
||||
if (!$mongoConfig) {
|
||||
throw new \Exception('MongoDB 配置不存在');
|
||||
}
|
||||
|
||||
$result['data']['config'] = [
|
||||
'driver' => $mongoConfig['driver'] ?? 'unknown',
|
||||
'database' => $mongoConfig['database'] ?? 'unknown',
|
||||
'dsn' => $mongoConfig['dsn'] ?? 'unknown',
|
||||
'has_username' => !empty($mongoConfig['username']),
|
||||
'has_password' => !empty($mongoConfig['password']),
|
||||
];
|
||||
|
||||
// 尝试使用 MongoDB 客户端直接连接
|
||||
try {
|
||||
// 构建包含认证信息的 DSN(如果配置了用户名和密码)
|
||||
$dsn = $mongoConfig['dsn'];
|
||||
if (!empty($mongoConfig['username']) && !empty($mongoConfig['password'])) {
|
||||
// 如果 DSN 中不包含认证信息,则添加
|
||||
if (strpos($dsn, '@') === false) {
|
||||
// 从 mongodb://host:port 格式转换为 mongodb://username:password@host:port/database
|
||||
$dsn = str_replace(
|
||||
'mongodb://',
|
||||
'mongodb://' . urlencode($mongoConfig['username']) . ':' . urlencode($mongoConfig['password']) . '@',
|
||||
$dsn
|
||||
);
|
||||
// 添加数据库名和认证源
|
||||
$dsn .= '/' . $mongoConfig['database'];
|
||||
if (!empty($mongoConfig['options']['authSource'])) {
|
||||
$dsn .= '?authSource=' . urlencode($mongoConfig['options']['authSource']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤掉空字符串的选项(MongoDB 客户端不允许空字符串)
|
||||
$options = array_filter($mongoConfig['options'] ?? [], function ($value) {
|
||||
return $value !== '';
|
||||
});
|
||||
|
||||
$client = new \MongoDB\Client(
|
||||
$dsn,
|
||||
$options
|
||||
);
|
||||
|
||||
// 尝试执行 ping 命令
|
||||
$adminDb = $client->selectDatabase('admin');
|
||||
$pingResult = $adminDb->command(['ping' => 1])->toArray();
|
||||
|
||||
$result['data']['connection'] = [
|
||||
'status' => 'connected',
|
||||
'ping' => 'ok',
|
||||
'server_info' => $client->getManager()->getServers(),
|
||||
];
|
||||
|
||||
// 尝试选择目标数据库并列出集合
|
||||
$targetDb = $client->selectDatabase($mongoConfig['database']);
|
||||
$collections = $targetDb->listCollections();
|
||||
$collectionNames = [];
|
||||
foreach ($collections as $collection) {
|
||||
$collectionNames[] = $collection->getName();
|
||||
}
|
||||
|
||||
$result['data']['test_query'] = [
|
||||
'database' => $mongoConfig['database'],
|
||||
'collections_count' => count($collectionNames),
|
||||
'collections' => $collectionNames,
|
||||
];
|
||||
|
||||
} catch (\MongoDB\Driver\Exception\Exception $e) {
|
||||
$result['data']['connection'] = [
|
||||
'status' => 'failed',
|
||||
'error' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
];
|
||||
$result['code'] = 500;
|
||||
$result['msg'] = 'MongoDB 连接失败';
|
||||
}
|
||||
|
||||
// 尝试使用 Repository 查询(如果连接成功)
|
||||
if ($result['data']['connection']['status'] === 'connected') {
|
||||
try {
|
||||
$userRepo = new \app\repository\UserProfileRepository();
|
||||
$count = $userRepo->newQuery()->count();
|
||||
$result['data']['repository_test'] = [
|
||||
'status' => 'ok',
|
||||
'user_profile_count' => $count,
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
$result['data']['repository_test'] = [
|
||||
'status' => 'failed',
|
||||
'error' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$result = [
|
||||
'code' => 500,
|
||||
'msg' => '测试失败: ' . $e->getMessage(),
|
||||
'data' => [
|
||||
'error' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return json($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,557 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\repository\UserProfileRepository;
|
||||
use app\service\UserService;
|
||||
use app\utils\ApiResponseHelper;
|
||||
use app\utils\DataMaskingHelper;
|
||||
use app\utils\LoggerHelper;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
|
||||
class UserController
|
||||
{
|
||||
public function hello(Request $request)
|
||||
/**
|
||||
* 创建用户
|
||||
*
|
||||
* POST /api/users
|
||||
*
|
||||
* 请求体示例:
|
||||
* {
|
||||
* "id_card": "110101199001011234",
|
||||
* "id_card_type": "身份证",
|
||||
* "name": "张三",
|
||||
* "phone": "13800138000",
|
||||
* "email": "zhangsan@example.com",
|
||||
* "gender": 1,
|
||||
* "birthday": "1990-01-01",
|
||||
* "address": "北京市朝阳区"
|
||||
* }
|
||||
*/
|
||||
public function store(Request $request): Response
|
||||
{
|
||||
$default_name = 'webman';
|
||||
// 从get请求里获得name参数,如果没有传递name参数则返回$default_name
|
||||
$name = $request->get('name', $default_name);
|
||||
// 向浏览器返回字符串
|
||||
return response('hello ' . $name);
|
||||
try {
|
||||
LoggerHelper::logRequest('POST', '/api/users');
|
||||
|
||||
$rawBody = $request->rawBody();
|
||||
|
||||
// 调试:记录原始请求体
|
||||
if (empty($rawBody)) {
|
||||
return ApiResponseHelper::error('请求体为空,请确保 Content-Type 为 application/json 并发送有效的 JSON 数据', 400);
|
||||
}
|
||||
|
||||
$body = json_decode($rawBody, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$errorMsg = '请求体必须是有效的 JSON 格式';
|
||||
$jsonError = json_last_error_msg();
|
||||
if ($jsonError) {
|
||||
$errorMsg .= ': ' . $jsonError;
|
||||
}
|
||||
// 开发环境输出更多调试信息
|
||||
if (getenv('APP_DEBUG') === 'true') {
|
||||
$errorMsg .= ' (原始请求体: ' . substr($rawBody, 0, 200) . ')';
|
||||
}
|
||||
return ApiResponseHelper::error($errorMsg, 400);
|
||||
}
|
||||
|
||||
$userService = new UserService(new UserProfileRepository());
|
||||
$result = $userService->createUser($body);
|
||||
|
||||
return ApiResponseHelper::success($result, '用户创建成功');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return ApiResponseHelper::error($e->getMessage(), 400);
|
||||
} catch (\Throwable $e) {
|
||||
return ApiResponseHelper::exception($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户信息
|
||||
*
|
||||
* GET /api/users/{user_id}?decrypt_id_card=1
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function show(Request $request): Response
|
||||
{
|
||||
try {
|
||||
// 从请求路径中解析 user_id
|
||||
$path = $request->path();
|
||||
if (preg_match('#/api/users/([^/]+)#', $path, $matches)) {
|
||||
$userId = $matches[1];
|
||||
} else {
|
||||
$userId = $request->get('user_id');
|
||||
if (!$userId) {
|
||||
throw new \InvalidArgumentException('缺少 user_id 参数');
|
||||
}
|
||||
}
|
||||
|
||||
LoggerHelper::logRequest('GET', $path, ['user_id' => $userId]);
|
||||
|
||||
// 检查是否需要解密身份证(需要权限控制,这里简单用参数控制)
|
||||
$decryptIdCard = (bool)$request->get('decrypt_id_card', false);
|
||||
|
||||
$userService = new UserService(new UserProfileRepository());
|
||||
$user = $userService->getUserById($userId, $decryptIdCard);
|
||||
|
||||
if (!$user) {
|
||||
return ApiResponseHelper::error('用户不存在', 404, 404);
|
||||
}
|
||||
|
||||
// 如果不需要解密身份证,对敏感字段进行脱敏
|
||||
if (!$decryptIdCard) {
|
||||
$user = DataMaskingHelper::maskArray($user, ['phone', 'email']);
|
||||
}
|
||||
|
||||
LoggerHelper::logBusiness('get_user_info', [
|
||||
'user_id' => $userId,
|
||||
'decrypt_id_card' => $decryptIdCard,
|
||||
]);
|
||||
|
||||
return ApiResponseHelper::success($user);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return ApiResponseHelper::error($e->getMessage(), 400);
|
||||
} catch (\Throwable $e) {
|
||||
return ApiResponseHelper::exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
*
|
||||
* PUT /api/users/{user_id}
|
||||
*
|
||||
* 请求体示例:
|
||||
* {
|
||||
* "name": "张三",
|
||||
* "phone": "13800138000",
|
||||
* "email": "zhangsan@example.com",
|
||||
* "gender": 1,
|
||||
* "birthday": "1990-01-01",
|
||||
* "address": "北京市朝阳区",
|
||||
* "status": 0
|
||||
* }
|
||||
*/
|
||||
public function update(Request $request): Response
|
||||
{
|
||||
try {
|
||||
// 从请求路径中解析 user_id
|
||||
$path = $request->path();
|
||||
if (preg_match('#/api/users/([^/]+)#', $path, $matches)) {
|
||||
$userId = $matches[1];
|
||||
} else {
|
||||
$userId = $request->get('user_id');
|
||||
if (!$userId) {
|
||||
throw new \InvalidArgumentException('缺少 user_id 参数');
|
||||
}
|
||||
}
|
||||
|
||||
LoggerHelper::logRequest('PUT', $path, ['user_id' => $userId]);
|
||||
|
||||
$rawBody = $request->rawBody();
|
||||
|
||||
// 调试:记录原始请求体
|
||||
if (empty($rawBody)) {
|
||||
return ApiResponseHelper::error('请求体为空,请确保 Content-Type 为 application/json 并发送有效的 JSON 数据', 400);
|
||||
}
|
||||
|
||||
$body = json_decode($rawBody, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$errorMsg = '请求体必须是有效的 JSON 格式';
|
||||
$jsonError = json_last_error_msg();
|
||||
if ($jsonError) {
|
||||
$errorMsg .= ': ' . $jsonError;
|
||||
}
|
||||
// 开发环境输出更多调试信息
|
||||
if (getenv('APP_DEBUG') === 'true') {
|
||||
$errorMsg .= ' (原始请求体: ' . substr($rawBody, 0, 200) . ')';
|
||||
}
|
||||
return ApiResponseHelper::error($errorMsg, 400);
|
||||
}
|
||||
|
||||
if (empty($body)) {
|
||||
return ApiResponseHelper::error('请求体不能为空', 400);
|
||||
}
|
||||
|
||||
$userService = new UserService(new UserProfileRepository());
|
||||
$result = $userService->updateUser($userId, $body);
|
||||
|
||||
// 脱敏处理
|
||||
$result = DataMaskingHelper::maskArray($result, ['phone', 'email']);
|
||||
|
||||
return ApiResponseHelper::success($result, '用户更新成功');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return ApiResponseHelper::error($e->getMessage(), 400);
|
||||
} catch (\Throwable $e) {
|
||||
return ApiResponseHelper::exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密身份证号
|
||||
*
|
||||
* GET /api/users/{user_id}/decrypt-id-card
|
||||
*/
|
||||
public function decryptIdCard(Request $request): Response
|
||||
{
|
||||
try {
|
||||
// 从请求路径中解析 user_id
|
||||
$path = $request->path();
|
||||
if (preg_match('#/api/users/([^/]+)/decrypt-id-card#', $path, $matches)) {
|
||||
$userId = $matches[1];
|
||||
} else {
|
||||
$userId = $request->get('user_id');
|
||||
if (!$userId) {
|
||||
throw new \InvalidArgumentException('缺少 user_id 参数');
|
||||
}
|
||||
}
|
||||
|
||||
LoggerHelper::logRequest('GET', $path, ['user_id' => $userId]);
|
||||
|
||||
$userService = new UserService(new UserProfileRepository());
|
||||
$user = $userService->getUserById($userId, true); // 强制解密
|
||||
|
||||
if (!$user) {
|
||||
return ApiResponseHelper::error('用户不存在', 404, 404);
|
||||
}
|
||||
|
||||
LoggerHelper::logBusiness('decrypt_id_card', [
|
||||
'user_id' => $userId,
|
||||
]);
|
||||
|
||||
return ApiResponseHelper::success([
|
||||
'user_id' => $user['user_id'],
|
||||
'id_card' => $user['id_card'] ?? ''
|
||||
]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return ApiResponseHelper::error($e->getMessage(), 400);
|
||||
} catch (\Throwable $e) {
|
||||
return ApiResponseHelper::exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户(软删除)
|
||||
*
|
||||
* DELETE /api/users/{user_id}
|
||||
*/
|
||||
public function destroy(Request $request): Response
|
||||
{
|
||||
try {
|
||||
// 从请求路径中解析 user_id
|
||||
$path = $request->path();
|
||||
if (preg_match('#/api/users/([^/]+)#', $path, $matches)) {
|
||||
$userId = $matches[1];
|
||||
} else {
|
||||
$userId = $request->get('user_id');
|
||||
if (!$userId) {
|
||||
throw new \InvalidArgumentException('缺少 user_id 参数');
|
||||
}
|
||||
}
|
||||
|
||||
LoggerHelper::logRequest('DELETE', $path, ['user_id' => $userId]);
|
||||
|
||||
$userService = new UserService(new UserProfileRepository());
|
||||
$userService->deleteUser($userId);
|
||||
|
||||
return ApiResponseHelper::success(null, '用户删除成功');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return ApiResponseHelper::error($e->getMessage(), 400);
|
||||
} catch (\Throwable $e) {
|
||||
return ApiResponseHelper::exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索用户(支持多种搜索条件组合)
|
||||
*
|
||||
* POST /api/users/search
|
||||
*
|
||||
* 支持以下搜索方式:
|
||||
* 1. 基础字段搜索:姓名、手机号、邮箱、身份证号等
|
||||
* 2. 标签筛选:根据用户标签筛选
|
||||
* 3. 组合搜索:基础字段 + 标签筛选
|
||||
*
|
||||
* 请求体示例1(姓名模糊搜索):
|
||||
* {
|
||||
* "name": "张三",
|
||||
* "page": 1,
|
||||
* "page_size": 20
|
||||
* }
|
||||
*
|
||||
* 请求体示例2(组合搜索:姓名 + 手机号):
|
||||
* {
|
||||
* "name": "张",
|
||||
* "phone": "138",
|
||||
* "page": 1,
|
||||
* "page_size": 20
|
||||
* }
|
||||
*
|
||||
* 请求体示例3(根据标签筛选):
|
||||
* {
|
||||
* "tag_conditions": [
|
||||
* {
|
||||
* "tag_code": "high_consumer",
|
||||
* "operator": "=",
|
||||
* "value": "high"
|
||||
* }
|
||||
* ],
|
||||
* "logic": "AND",
|
||||
* "page": 1,
|
||||
* "page_size": 20
|
||||
* }
|
||||
*
|
||||
* 请求体示例4(组合搜索:基础字段 + 标签):
|
||||
* {
|
||||
* "name": "张",
|
||||
* "min_total_amount": 1000,
|
||||
* "tag_conditions": [
|
||||
* {
|
||||
* "tag_code": "active_user",
|
||||
* "operator": "=",
|
||||
* "value": "active"
|
||||
* }
|
||||
* ],
|
||||
* "page": 1,
|
||||
* "page_size": 20
|
||||
* }
|
||||
*/
|
||||
public function search(Request $request): Response
|
||||
{
|
||||
try {
|
||||
LoggerHelper::logRequest('POST', '/api/users/search');
|
||||
|
||||
$rawBody = $request->rawBody();
|
||||
|
||||
// 调试:记录原始请求体
|
||||
if (empty($rawBody)) {
|
||||
return ApiResponseHelper::error('请求体为空,请确保 Content-Type 为 application/json 并发送有效的 JSON 数据', 400);
|
||||
}
|
||||
|
||||
$body = json_decode($rawBody, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$errorMsg = '请求体必须是有效的 JSON 格式';
|
||||
$jsonError = json_last_error_msg();
|
||||
if ($jsonError) {
|
||||
$errorMsg .= ': ' . $jsonError;
|
||||
}
|
||||
// 开发环境输出更多调试信息
|
||||
if (getenv('APP_DEBUG') === 'true') {
|
||||
$errorMsg .= ' (原始请求体: ' . substr($rawBody, 0, 200) . ')';
|
||||
}
|
||||
return ApiResponseHelper::error($errorMsg, 400);
|
||||
}
|
||||
|
||||
$page = (int)($body['page'] ?? 1);
|
||||
$pageSize = (int)($body['page_size'] ?? 20);
|
||||
|
||||
if ($page < 1) {
|
||||
$page = 1;
|
||||
}
|
||||
if ($pageSize < 1 || $pageSize > 100) {
|
||||
$pageSize = 20;
|
||||
}
|
||||
|
||||
$userService = new UserService(new UserProfileRepository());
|
||||
|
||||
// 情况1:仅根据身份证号查找(返回单个用户,不分页)
|
||||
if (!empty($body['id_card']) && empty($body['tag_conditions']) && empty($body['name']) && empty($body['phone']) && empty($body['email'])) {
|
||||
$user = $userService->findUserByIdCard($body['id_card']);
|
||||
|
||||
if (!$user) {
|
||||
return ApiResponseHelper::error('未找到该身份证号对应的用户', 404, 404);
|
||||
}
|
||||
|
||||
// 脱敏处理
|
||||
$user = DataMaskingHelper::maskArray($user, ['phone', 'email']);
|
||||
|
||||
LoggerHelper::logBusiness('search_user_by_id_card', [
|
||||
'found' => true,
|
||||
]);
|
||||
|
||||
return ApiResponseHelper::success($user);
|
||||
}
|
||||
|
||||
// 情况2:根据标签筛选用户(可能结合基础字段搜索)
|
||||
if (!empty($body['tag_conditions'])) {
|
||||
$tagService = new \app\service\TagService(
|
||||
new \app\repository\TagDefinitionRepository(),
|
||||
new UserProfileRepository(),
|
||||
new \app\repository\UserTagRepository(),
|
||||
new \app\repository\TagHistoryRepository(),
|
||||
new \app\service\TagRuleEngine\SimpleRuleEngine()
|
||||
);
|
||||
|
||||
$conditions = $body['tag_conditions'];
|
||||
$logic = $body['logic'] ?? 'AND';
|
||||
$includeUserInfo = true; // 标签筛选需要用户信息
|
||||
|
||||
// 验证条件格式
|
||||
foreach ($conditions as $condition) {
|
||||
if (!isset($condition['tag_code']) || !isset($condition['operator']) || !isset($condition['value'])) {
|
||||
throw new \InvalidArgumentException('每个条件必须包含 tag_code、operator 和 value 字段');
|
||||
}
|
||||
}
|
||||
|
||||
// 先根据标签筛选用户
|
||||
$tagResult = $tagService->filterUsersByTags(
|
||||
$conditions,
|
||||
$logic,
|
||||
1, // 先获取所有符合条件的用户ID
|
||||
10000, // 临时设置大值,获取所有用户ID
|
||||
true
|
||||
);
|
||||
|
||||
$userIds = array_column($tagResult['users'], 'user_id');
|
||||
|
||||
if (empty($userIds)) {
|
||||
return ApiResponseHelper::success([
|
||||
'users' => [],
|
||||
'total' => 0,
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
'total_pages' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
// 如果有基础字段搜索条件,进一步筛选
|
||||
$baseConditions = [];
|
||||
if (!empty($body['name'])) {
|
||||
$baseConditions['name'] = $body['name'];
|
||||
}
|
||||
if (!empty($body['phone'])) {
|
||||
$baseConditions['phone'] = $body['phone'];
|
||||
$baseConditions['phone_exact'] = $body['phone_exact'] ?? false;
|
||||
}
|
||||
if (!empty($body['email'])) {
|
||||
$baseConditions['email'] = $body['email'];
|
||||
$baseConditions['email_exact'] = $body['email_exact'] ?? false;
|
||||
}
|
||||
if (isset($body['gender']) && $body['gender'] !== '') {
|
||||
$baseConditions['gender'] = $body['gender'];
|
||||
}
|
||||
if (isset($body['status']) && $body['status'] !== '') {
|
||||
$baseConditions['status'] = $body['status'];
|
||||
}
|
||||
if (isset($body['min_total_amount'])) {
|
||||
$baseConditions['min_total_amount'] = $body['min_total_amount'];
|
||||
}
|
||||
if (isset($body['max_total_amount'])) {
|
||||
$baseConditions['max_total_amount'] = $body['max_total_amount'];
|
||||
}
|
||||
if (isset($body['min_total_count'])) {
|
||||
$baseConditions['min_total_count'] = $body['min_total_count'];
|
||||
}
|
||||
if (isset($body['max_total_count'])) {
|
||||
$baseConditions['max_total_count'] = $body['max_total_count'];
|
||||
}
|
||||
|
||||
// 如果有基础字段条件,需要进一步筛选
|
||||
if (!empty($baseConditions)) {
|
||||
$baseConditions['user_ids'] = $userIds; // 限制在标签筛选的用户范围内
|
||||
$result = $userService->searchUsers($baseConditions, $page, $pageSize);
|
||||
} else {
|
||||
// 没有基础字段条件,直接使用标签筛选结果并分页
|
||||
$total = count($userIds);
|
||||
$offset = ($page - 1) * $pageSize;
|
||||
$pagedUserIds = array_slice($userIds, $offset, $pageSize);
|
||||
|
||||
// 获取用户详细信息
|
||||
$users = [];
|
||||
foreach ($pagedUserIds as $userId) {
|
||||
$user = $userService->getUserById($userId, false);
|
||||
if ($user) {
|
||||
$users[] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$result = [
|
||||
'users' => $users,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
'total_pages' => (int)ceil($total / $pageSize),
|
||||
];
|
||||
}
|
||||
|
||||
// 对返回的用户信息进行脱敏处理
|
||||
if (isset($result['users']) && is_array($result['users'])) {
|
||||
foreach ($result['users'] as &$user) {
|
||||
$user = DataMaskingHelper::maskArray($user, ['phone', 'email']);
|
||||
}
|
||||
unset($user);
|
||||
}
|
||||
|
||||
LoggerHelper::logBusiness('search_users_by_tags', [
|
||||
'conditions_count' => count($conditions),
|
||||
'base_conditions' => !empty($baseConditions),
|
||||
'result_count' => $result['total'] ?? 0,
|
||||
]);
|
||||
|
||||
return ApiResponseHelper::success($result);
|
||||
}
|
||||
|
||||
// 情况3:仅基础字段搜索(无标签条件)
|
||||
$baseConditions = [];
|
||||
if (!empty($body['name'])) {
|
||||
$baseConditions['name'] = $body['name'];
|
||||
}
|
||||
if (!empty($body['phone'])) {
|
||||
$baseConditions['phone'] = $body['phone'];
|
||||
$baseConditions['phone_exact'] = $body['phone_exact'] ?? false;
|
||||
}
|
||||
if (!empty($body['email'])) {
|
||||
$baseConditions['email'] = $body['email'];
|
||||
$baseConditions['email_exact'] = $body['email_exact'] ?? false;
|
||||
}
|
||||
if (!empty($body['id_card'])) {
|
||||
$baseConditions['id_card'] = $body['id_card'];
|
||||
}
|
||||
if (isset($body['gender']) && $body['gender'] !== '') {
|
||||
$baseConditions['gender'] = $body['gender'];
|
||||
}
|
||||
if (isset($body['status']) && $body['status'] !== '') {
|
||||
$baseConditions['status'] = $body['status'];
|
||||
}
|
||||
if (isset($body['min_total_amount'])) {
|
||||
$baseConditions['min_total_amount'] = $body['min_total_amount'];
|
||||
}
|
||||
if (isset($body['max_total_amount'])) {
|
||||
$baseConditions['max_total_amount'] = $body['max_total_amount'];
|
||||
}
|
||||
if (isset($body['min_total_count'])) {
|
||||
$baseConditions['min_total_count'] = $body['min_total_count'];
|
||||
}
|
||||
if (isset($body['max_total_count'])) {
|
||||
$baseConditions['max_total_count'] = $body['max_total_count'];
|
||||
}
|
||||
|
||||
if (empty($baseConditions)) {
|
||||
return ApiResponseHelper::error('请提供至少一个搜索条件', 400);
|
||||
}
|
||||
|
||||
$result = $userService->searchUsers($baseConditions, $page, $pageSize);
|
||||
|
||||
// 对返回的用户信息进行脱敏处理
|
||||
if (isset($result['users']) && is_array($result['users'])) {
|
||||
foreach ($result['users'] as &$user) {
|
||||
$user = DataMaskingHelper::maskArray($user, ['phone', 'email']);
|
||||
}
|
||||
unset($user);
|
||||
}
|
||||
|
||||
LoggerHelper::logBusiness('search_users_by_base_fields', [
|
||||
'conditions' => array_keys($baseConditions),
|
||||
'result_count' => $result['total'] ?? 0,
|
||||
]);
|
||||
|
||||
return ApiResponseHelper::success($result);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return ApiResponseHelper::error($e->getMessage(), 400);
|
||||
} catch (\Throwable $e) {
|
||||
return ApiResponseHelper::exception($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,12 @@
|
||||
"php": ">=8.1",
|
||||
"workerman/webman-framework": "^2.1",
|
||||
"monolog/monolog": "^2.0",
|
||||
"mongodb/laravel-mongodb": "^4.0"
|
||||
"mongodb/laravel-mongodb": "^4.0",
|
||||
"vlucas/phpdotenv": "^5.6",
|
||||
"predis/predis": "^2.0",
|
||||
"dragonmantank/cron-expression": "^3.6",
|
||||
"php-amqplib/php-amqplib": "^3.7",
|
||||
"ramsey/uuid": "^4.7"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-event": "For better performance. "
|
||||
|
||||
896
Moncter/composer.lock
generated
896
Moncter/composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b36fd3581fc1bf43e25a6294dd7efc58",
|
||||
"content-hash": "6cafa2c36c31a9f9ddfcf8df3e7da924",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
@@ -225,6 +225,132 @@
|
||||
],
|
||||
"time": "2025-08-10T19:31:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dragonmantank/cron-expression",
|
||||
"version": "v3.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dragonmantank/cron-expression.git",
|
||||
"reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/d61a8a9604ec1f8c3d150d09db6ce98b32675013",
|
||||
"reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.2|^8.3|^8.4|^8.5"
|
||||
},
|
||||
"replace": {
|
||||
"mtdowling/cron-expression": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.4.3",
|
||||
"phpstan/phpstan": "^1.12.32|^2.1.31",
|
||||
"phpunit/phpunit": "^8.5.48|^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cron\\": "src/Cron/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Chris Tankersley",
|
||||
"email": "chris@ctankersley.com",
|
||||
"homepage": "https://github.com/dragonmantank"
|
||||
}
|
||||
],
|
||||
"description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due",
|
||||
"keywords": [
|
||||
"cron",
|
||||
"schedule"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dragonmantank/cron-expression/issues",
|
||||
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/dragonmantank",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-31T18:51:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
"version": "v1.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GrahamCampbell/Result-Type.git",
|
||||
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945",
|
||||
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GrahamCampbell\\ResultType\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
}
|
||||
],
|
||||
"description": "An Implementation Of The Result Type",
|
||||
"keywords": [
|
||||
"Graham Campbell",
|
||||
"GrahamCampbell",
|
||||
"Result Type",
|
||||
"Result-Type",
|
||||
"result"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
|
||||
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-20T21:45:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/bus",
|
||||
"version": "v11.46.1",
|
||||
@@ -1335,6 +1461,453 @@
|
||||
},
|
||||
"time": "2018-02-13T20:26:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v3.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/constant_time_encoding.git",
|
||||
"reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77",
|
||||
"reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0",
|
||||
"nikic/php-fuzzer": "^0",
|
||||
"phpunit/phpunit": "^9|^10|^11",
|
||||
"vimeo/psalm": "^4|^5|^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ParagonIE\\ConstantTime\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Steve 'Sc00bz' Thomas",
|
||||
"email": "steve@tobtu.com",
|
||||
"homepage": "https://www.tobtu.com",
|
||||
"role": "Original Developer"
|
||||
}
|
||||
],
|
||||
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
|
||||
"keywords": [
|
||||
"base16",
|
||||
"base32",
|
||||
"base32_decode",
|
||||
"base32_encode",
|
||||
"base64",
|
||||
"base64_decode",
|
||||
"base64_encode",
|
||||
"bin2hex",
|
||||
"encoding",
|
||||
"hex",
|
||||
"hex2bin",
|
||||
"rfc4648"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
|
||||
"source": "https://github.com/paragonie/constant_time_encoding"
|
||||
},
|
||||
"time": "2025-09-24T15:06:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v9.99.100",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"polyfill",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/random_compat/issues",
|
||||
"source": "https://github.com/paragonie/random_compat"
|
||||
},
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-amqplib/php-amqplib",
|
||||
"version": "v3.7.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-amqplib/php-amqplib.git",
|
||||
"reference": "381b6f7c600e0e0c7463cdd7f7a1a3bc6268e5fd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/381b6f7c600e0e0c7463cdd7f7a1a3bc6268e5fd",
|
||||
"reference": "381b6f7c600e0e0c7463cdd7f7a1a3bc6268e5fd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"ext-sockets": "*",
|
||||
"php": "^7.2||^8.0",
|
||||
"phpseclib/phpseclib": "^2.0|^3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"php": "7.4.0 - 7.4.1"
|
||||
},
|
||||
"replace": {
|
||||
"videlalvaro/php-amqplib": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"nategood/httpful": "^0.2.20",
|
||||
"phpunit/phpunit": "^7.5|^9.5",
|
||||
"squizlabs/php_codesniffer": "^3.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpAmqpLib\\": "PhpAmqpLib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alvaro Videla",
|
||||
"role": "Original Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Raúl Araya",
|
||||
"email": "nubeiro@gmail.com",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Luke Bakken",
|
||||
"email": "luke@bakken.io",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Ramūnas Dronga",
|
||||
"email": "github@ramuno.lt",
|
||||
"role": "Maintainer"
|
||||
}
|
||||
],
|
||||
"description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
|
||||
"homepage": "https://github.com/php-amqplib/php-amqplib/",
|
||||
"keywords": [
|
||||
"message",
|
||||
"queue",
|
||||
"rabbitmq"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-amqplib/php-amqplib/issues",
|
||||
"source": "https://github.com/php-amqplib/php-amqplib/tree/v3.7.4"
|
||||
},
|
||||
"time": "2025-11-23T17:00:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/php-option.git",
|
||||
"reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d",
|
||||
"reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpOption\\": "src/PhpOption/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Johannes M. Schmitt",
|
||||
"email": "schmittjoh@gmail.com",
|
||||
"homepage": "https://github.com/schmittjoh"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
}
|
||||
],
|
||||
"description": "Option Type for PHP",
|
||||
"keywords": [
|
||||
"language",
|
||||
"option",
|
||||
"php",
|
||||
"type"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/schmittjoh/php-option/issues",
|
||||
"source": "https://github.com/schmittjoh/php-option/tree/1.9.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-21T11:53:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "3.0.48",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "64065a5679c50acb886e82c07aa139b0f757bb89"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/64065a5679c50acb886e82c07aa139b0f757bb89",
|
||||
"reference": "64065a5679c50acb886e82c07aa139b0f757bb89",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"paragonie/constant_time_encoding": "^1|^2|^3",
|
||||
"paragonie/random_compat": "^1.4|^2.0|^9.99.99",
|
||||
"php": ">=5.6.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Install the DOM extension to load XML formatted public keys.",
|
||||
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
||||
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
||||
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
||||
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"phpseclib/bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"phpseclib3\\": "phpseclib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jim Wigginton",
|
||||
"email": "terrafrost@php.net",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Patrick Monnerat",
|
||||
"email": "pm@datasphere.ch",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Fischer",
|
||||
"email": "bantu@phpbb.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Hans-Jürgen Petrich",
|
||||
"email": "petrich@tronic-media.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "graham@alt-three.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
|
||||
"homepage": "http://phpseclib.sourceforge.net",
|
||||
"keywords": [
|
||||
"BigInteger",
|
||||
"aes",
|
||||
"asn.1",
|
||||
"asn1",
|
||||
"blowfish",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"encryption",
|
||||
"rsa",
|
||||
"security",
|
||||
"sftp",
|
||||
"signature",
|
||||
"signing",
|
||||
"ssh",
|
||||
"twofish",
|
||||
"x.509",
|
||||
"x509"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.48"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/terrafrost",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpseclib",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-15T11:51:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "predis/predis",
|
||||
"version": "v2.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/predis/predis.git",
|
||||
"reference": "07105e050622ed80bd60808367ced9e379f31530"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/predis/predis/zipball/07105e050622ed80bd60808367ced9e379f31530",
|
||||
"reference": "07105e050622ed80bd60808367ced9e379f31530",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.3",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpcov": "^6.0 || ^8.0",
|
||||
"phpunit/phpunit": "^8.0 || ^9.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Predis\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Till Krüss",
|
||||
"homepage": "https://till.im",
|
||||
"role": "Maintainer"
|
||||
}
|
||||
],
|
||||
"description": "A flexible and feature-complete Redis/Valkey client for PHP.",
|
||||
"homepage": "http://github.com/predis/predis",
|
||||
"keywords": [
|
||||
"nosql",
|
||||
"predis",
|
||||
"redis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/predis/predis/issues",
|
||||
"source": "https://github.com/predis/predis/tree/v2.4.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/tillkruss",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-12T18:00:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/clock",
|
||||
"version": "1.0.0",
|
||||
@@ -1537,6 +2110,160 @@
|
||||
},
|
||||
"time": "2021-10-29T13:26:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
"version": "2.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/collection.git",
|
||||
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"ergebnis/composer-normalize": "^2.45",
|
||||
"fakerphp/faker": "^1.24",
|
||||
"hamcrest/hamcrest-php": "^2.0",
|
||||
"jangregor/phpstan-prophecy": "^2.1",
|
||||
"mockery/mockery": "^1.6",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4",
|
||||
"phpspec/prophecy-phpunit": "^2.3",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-mockery": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"ramsey/coding-standard": "^2.3",
|
||||
"ramsey/conventional-commits": "^1.6",
|
||||
"roave/security-advisories": "dev-latest"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"captainhook": {
|
||||
"force-install": true
|
||||
},
|
||||
"ramsey/conventional-commits": {
|
||||
"configFile": "conventional-commits.json"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ramsey\\Collection\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ben Ramsey",
|
||||
"email": "ben@benramsey.com",
|
||||
"homepage": "https://benramsey.com"
|
||||
}
|
||||
],
|
||||
"description": "A PHP library for representing and manipulating collections.",
|
||||
"keywords": [
|
||||
"array",
|
||||
"collection",
|
||||
"hash",
|
||||
"map",
|
||||
"queue",
|
||||
"set"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/collection/issues",
|
||||
"source": "https://github.com/ramsey/collection/tree/2.1.1"
|
||||
},
|
||||
"time": "2025-03-22T05:38:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.9.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "8429c78ca35a09f27565311b98101e2826affde0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0",
|
||||
"reference": "8429c78ca35a09f27565311b98101e2826affde0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
|
||||
"php": "^8.0",
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
},
|
||||
"replace": {
|
||||
"rhumsaa/uuid": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/captainhook": "^5.25",
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"ergebnis/composer-normalize": "^2.47",
|
||||
"mockery/mockery": "^1.6",
|
||||
"paragonie/random-lib": "^2",
|
||||
"php-mock/php-mock": "^2.6",
|
||||
"php-mock/php-mock-mockery": "^1.5",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4.0",
|
||||
"phpbench/phpbench": "^1.2.14",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-mockery": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"slevomat/coding-standard": "^8.18",
|
||||
"squizlabs/php_codesniffer": "^3.13"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
|
||||
"ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
|
||||
"ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
|
||||
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
|
||||
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"captainhook": {
|
||||
"force-install": true
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Ramsey\\Uuid\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
|
||||
"keywords": [
|
||||
"guid",
|
||||
"identifier",
|
||||
"uuid"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid/issues",
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.9.2"
|
||||
},
|
||||
"time": "2025-12-14T04:43:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
"version": "v7.3.0",
|
||||
@@ -1678,6 +2405,89 @@
|
||||
],
|
||||
"time": "2024-09-25T14:21:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.33.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.33.0",
|
||||
@@ -2185,6 +2995,90 @@
|
||||
],
|
||||
"time": "2024-09-27T08:32:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v5.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||
"reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af",
|
||||
"reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pcre": "*",
|
||||
"graham-campbell/result-type": "^1.1.3",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.3",
|
||||
"symfony/polyfill-ctype": "^1.24",
|
||||
"symfony/polyfill-mbstring": "^1.24",
|
||||
"symfony/polyfill-php80": "^1.24"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-filter": "*",
|
||||
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-filter": "Required to use the boolean validator."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dotenv\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Vance Lucas",
|
||||
"email": "vance@vancelucas.com",
|
||||
"homepage": "https://github.com/vlucas"
|
||||
}
|
||||
],
|
||||
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
|
||||
"keywords": [
|
||||
"dotenv",
|
||||
"env",
|
||||
"environment"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/vlucas/phpdotenv/issues",
|
||||
"source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-30T23:37:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "voku/portable-ascii",
|
||||
"version": "2.0.3",
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
return [
|
||||
'files' => [
|
||||
base_path() . '/app/functions.php',
|
||||
base_path() . '/support/Request.php',
|
||||
base_path() . '/support/Response.php',
|
||||
]
|
||||
|
||||
@@ -14,4 +14,5 @@
|
||||
|
||||
return [
|
||||
support\bootstrap\Session::class,
|
||||
support\bootstrap\MongoDB::class,
|
||||
];
|
||||
|
||||
@@ -9,17 +9,17 @@ return [
|
||||
// MongoDB 官方连接配置
|
||||
'mongodb' => [
|
||||
'driver' => 'mongodb',
|
||||
'dsn' => 'mongodb://127.0.0.1:27017', // 集群可写:mongodb://node1:27017,node2:27017
|
||||
'database' => 'Moncter', // 目标数据库名
|
||||
'username' => 'Moncter', // 无认证则省略
|
||||
'dsn' => 'mongodb://192.168.1.106:27017', // 集群可写:mongodb://node1:27017,node2:27017
|
||||
'database' => 'ckb', // 目标数据库名
|
||||
'username' => 'ckb', // 无认证则省略
|
||||
'password' => '123456', // 无认证则省略
|
||||
'options' => [
|
||||
'replicaSet' => '', // 副本集名称(无则留空)
|
||||
// 'replicaSet' => '', // 副本集名称(如果使用副本集,取消注释并填写名称)
|
||||
'ssl' => false, // 是否启用 SSL
|
||||
'connectTimeoutMS' => 3000, // 连接超时
|
||||
'socketTimeoutMS' => 5000, // 读写超时
|
||||
// 认证相关(若 MongoDB 启用认证)
|
||||
'authSource' => 'admin', // 认证数据库(默认 admin)
|
||||
'authSource' => 'ckb', // 认证数据库(默认 admin)
|
||||
'authMechanism' => 'SCRAM-SHA-256', // 认证机制(默认推荐)
|
||||
],
|
||||
],
|
||||
|
||||
@@ -28,5 +28,10 @@ return [
|
||||
],
|
||||
]
|
||||
],
|
||||
'processors' => [
|
||||
[
|
||||
'class' => app\utils\LogMaskingProcessor::class,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -58,5 +58,26 @@ return [
|
||||
'enable_memory_monitor' => DIRECTORY_SEPARATOR === '/',
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
// 数据采集任务调度器(从 config/data_collection_tasks.php 读取所有采集任务配置)
|
||||
'data_sync_scheduler' => [
|
||||
'handler' => app\process\DataSyncScheduler::class,
|
||||
'count' => 10, // Worker 进程数量(可根据任务数量调整)
|
||||
'reloadable' => false,
|
||||
],
|
||||
// 数据同步 Worker(消费 RabbitMQ 消息队列)
|
||||
// 处理从采集任务推送过来的数据,写入目标数据库
|
||||
'data_sync_worker' => [
|
||||
'handler' => app\process\DataSyncWorker::class,
|
||||
'count' => 20, // Worker 进程数量(可根据消息量调整)
|
||||
'reloadable' => false,
|
||||
],
|
||||
// 标签计算 Worker(消费 RabbitMQ 消息队列)
|
||||
// 根据用户数据计算标签值
|
||||
'tag_calculation_worker' => [
|
||||
'handler' => app\process\TagCalculationWorker::class,
|
||||
'count' => 2, // Worker 进程数量(可根据消息量调整)
|
||||
'reloadable' => false,
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -15,7 +15,106 @@
|
||||
use Webman\Route;
|
||||
|
||||
|
||||
// 数据库连接测试接口
|
||||
Route::get('/api/test/db', [app\controller\IndexController::class, 'testDb']);
|
||||
|
||||
// ============================================
|
||||
// 用户相关接口(RESTful)
|
||||
// ============================================
|
||||
Route::post('/api/users', [app\controller\UserController::class, 'store']); // 创建用户
|
||||
Route::get('/api/users/{user_id}', [app\controller\UserController::class, 'show']); // 查询用户
|
||||
Route::put('/api/users/{user_id}', [app\controller\UserController::class, 'update']); // 更新用户
|
||||
Route::delete('/api/users/{user_id}', [app\controller\UserController::class, 'destroy']); // 删除用户
|
||||
Route::get('/api/users/{user_id}/decrypt-id-card', [app\controller\UserController::class, 'decryptIdCard']); // 解密身份证
|
||||
Route::post('/api/users/search', [app\controller\UserController::class, 'search']); // 搜索用户(复杂查询)
|
||||
|
||||
// ============================================
|
||||
// 用户标签相关接口(RESTful)
|
||||
// ============================================
|
||||
Route::get('/api/users/{user_id}/tags', [app\controller\TagController::class, 'listByUser']); // 查询用户标签
|
||||
Route::put('/api/users/{user_id}/tags', [app\controller\TagController::class, 'calculate']); // 更新/计算用户标签
|
||||
Route::delete('/api/users/{user_id}/tags/{tag_id}', [app\controller\TagController::class, 'destroy']); // 删除用户标签
|
||||
|
||||
// ============================================
|
||||
// 消费记录相关接口
|
||||
// ============================================
|
||||
Route::post('/api/consumption/record', [app\controller\ConsumptionController::class, 'store']); // 创建消费记录
|
||||
|
||||
// ============================================
|
||||
// 标签定义相关接口(管理接口)
|
||||
// ============================================
|
||||
Route::post('/api/tags/filter', [app\controller\TagController::class, 'filter']); // 根据标签筛选用户
|
||||
Route::get('/api/tags/statistics', [app\controller\TagController::class, 'statistics']); // 获取标签统计信息
|
||||
Route::get('/api/tags/history', [app\controller\TagController::class, 'history']); // 获取标签历史记录
|
||||
Route::post('/api/tag-definitions/batch', [app\controller\TagController::class, 'init']); // 批量初始化标签定义
|
||||
Route::get('/api/tag-definitions', [app\controller\TagDefinitionController::class, 'list']); // 获取标签定义列表
|
||||
Route::post('/api/tag-definitions', [app\controller\TagDefinitionController::class, 'create']); // 创建标签定义
|
||||
Route::get('/api/tag-definitions/{tag_id}', [app\controller\TagDefinitionController::class, 'detail']); // 获取标签定义详情
|
||||
Route::put('/api/tag-definitions/{tag_id}', [app\controller\TagDefinitionController::class, 'update']); // 更新标签定义
|
||||
Route::delete('/api/tag-definitions/{tag_id}', [app\controller\TagDefinitionController::class, 'delete']); // 删除标签定义
|
||||
|
||||
// ============================================
|
||||
// 标签任务管理接口
|
||||
// ============================================
|
||||
Route::post('/api/tag-tasks', [app\controller\TagTaskController::class, 'create']); // 创建标签任务
|
||||
Route::put('/api/tag-tasks/{task_id}', [app\controller\TagTaskController::class, 'update']); // 更新标签任务
|
||||
Route::delete('/api/tag-tasks/{task_id}', [app\controller\TagTaskController::class, 'delete']); // 删除标签任务
|
||||
Route::get('/api/tag-tasks', [app\controller\TagTaskController::class, 'list']); // 标签任务列表
|
||||
Route::get('/api/tag-tasks/{task_id}', [app\controller\TagTaskController::class, 'detail']); // 标签任务详情
|
||||
Route::get('/api/tag-tasks/{task_id}/executions', [app\controller\TagTaskController::class, 'executions']); // 获取任务执行记录
|
||||
Route::post('/api/tag-tasks/{task_id}/start', [app\controller\TagTaskController::class, 'start']); // 启动标签任务
|
||||
Route::post('/api/tag-tasks/{task_id}/pause', [app\controller\TagTaskController::class, 'pause']); // 暂停标签任务
|
||||
Route::post('/api/tag-tasks/{task_id}/stop', [app\controller\TagTaskController::class, 'stop']); // 停止标签任务
|
||||
|
||||
// ============================================
|
||||
// 身份合并相关接口(场景4:手机号发现身份证后合并)
|
||||
// ============================================
|
||||
Route::post('/api/person-merge/phone-to-id-card', [app\controller\PersonMergeController::class, 'mergePhoneToIdCard']); // 合并手机号到身份证
|
||||
Route::post('/api/person-merge/temporary-to-formal', [app\controller\PersonMergeController::class, 'mergeTemporaryToFormal']); // 合并临时人到正式人
|
||||
|
||||
// ============================================
|
||||
// 数据库同步相关接口
|
||||
// ============================================
|
||||
Route::get('/database-sync/dashboard', [app\controller\DatabaseSyncController::class, 'dashboard']); // 同步进度看板页面
|
||||
Route::get('/api/database-sync/progress', [app\controller\DatabaseSyncController::class, 'progress']); // 查询同步进度
|
||||
Route::get('/api/database-sync/stats', [app\controller\DatabaseSyncController::class, 'stats']); // 查询同步统计
|
||||
Route::post('/api/database-sync/reset', [app\controller\DatabaseSyncController::class, 'reset']); // 重置同步进度
|
||||
Route::post('/api/database-sync/skip-error', [app\controller\DatabaseSyncController::class, 'skipError']); // 跳过错误数据库
|
||||
|
||||
// ============================================
|
||||
// 数据采集任务管理接口
|
||||
// ============================================
|
||||
Route::post('/api/data-collection-tasks', [app\controller\DataCollectionTaskController::class, 'create']); // 创建任务
|
||||
Route::put('/api/data-collection-tasks/{task_id}', [app\controller\DataCollectionTaskController::class, 'update']); // 更新任务
|
||||
Route::delete('/api/data-collection-tasks/{task_id}', [app\controller\DataCollectionTaskController::class, 'delete']); // 删除任务
|
||||
Route::get('/api/data-collection-tasks', [app\controller\DataCollectionTaskController::class, 'list']); // 任务列表
|
||||
Route::get('/api/data-collection-tasks/data-sources', [app\controller\DataCollectionTaskController::class, 'getDataSources']); // 获取数据源列表
|
||||
Route::get('/api/data-collection-tasks/{task_id}', [app\controller\DataCollectionTaskController::class, 'detail']); // 任务详情
|
||||
Route::get('/api/data-collection-tasks/{task_id}/progress', [app\controller\DataCollectionTaskController::class, 'progress']); // 任务进度
|
||||
Route::post('/api/data-collection-tasks/{task_id}/start', [app\controller\DataCollectionTaskController::class, 'start']); // 启动任务
|
||||
Route::post('/api/data-collection-tasks/{task_id}/pause', [app\controller\DataCollectionTaskController::class, 'pause']); // 暂停任务
|
||||
Route::post('/api/data-collection-tasks/{task_id}/stop', [app\controller\DataCollectionTaskController::class, 'stop']); // 停止任务
|
||||
Route::get('/api/data-collection-tasks/data-sources/{data_source_id}/databases', [app\controller\DataCollectionTaskController::class, 'getDatabases']); // 获取数据库列表
|
||||
Route::get('/api/data-collection-tasks/data-sources/{data_source_id}/databases/{database}/collections', [app\controller\DataCollectionTaskController::class, 'getCollections']); // 获取集合列表
|
||||
Route::get('/api/data-collection-tasks/data-sources/{data_source_id}/databases/{database}/collections/{collection}/fields', [app\controller\DataCollectionTaskController::class, 'getFields']); // 获取字段列表
|
||||
Route::get('/api/data-collection-tasks/handlers/{handler_type}/target-fields', [app\controller\DataCollectionTaskController::class, 'getHandlerTargetFields']); // 获取Handler的目标字段列表
|
||||
Route::post('/api/data-collection-tasks/preview-query', [app\controller\DataCollectionTaskController::class, 'previewQuery']); // 预览查询结果
|
||||
|
||||
// ============================================
|
||||
// 数据源管理接口
|
||||
// ============================================
|
||||
Route::get('/api/data-sources', [app\controller\DataSourceController::class, 'list']); // 获取数据源列表
|
||||
Route::get('/api/data-sources/{data_source_id}', [app\controller\DataSourceController::class, 'detail']); // 获取数据源详情
|
||||
Route::post('/api/data-sources', [app\controller\DataSourceController::class, 'create']); // 创建数据源
|
||||
Route::put('/api/data-sources/{data_source_id}', [app\controller\DataSourceController::class, 'update']); // 更新数据源
|
||||
Route::delete('/api/data-sources/{data_source_id}', [app\controller\DataSourceController::class, 'delete']); // 删除数据源
|
||||
Route::post('/api/data-sources/test-connection', [app\controller\DataSourceController::class, 'testConnection']); // 测试数据源连接
|
||||
|
||||
// ============================================
|
||||
// 人群快照相关接口
|
||||
// ============================================
|
||||
Route::get('/api/tag-cohorts', [app\controller\TagCohortController::class, 'list']); // 获取人群快照列表
|
||||
Route::get('/api/tag-cohorts/{cohort_id}', [app\controller\TagCohortController::class, 'detail']); // 获取人群快照详情
|
||||
Route::post('/api/tag-cohorts', [app\controller\TagCohortController::class, 'create']); // 创建人群快照
|
||||
Route::delete('/api/tag-cohorts/{cohort_id}', [app\controller\TagCohortController::class, 'delete']); // 删除人群快照
|
||||
Route::post('/api/tag-cohorts/{cohort_id}/export', [app\controller\TagCohortController::class, 'export']); // 导出人群快照
|
||||
54
Moncter/env.txt
Normal file
54
Moncter/env.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
# ============================================
|
||||
# 加密配置
|
||||
# ============================================
|
||||
|
||||
# AES 加密密钥(至少32字符,建议使用随机生成的强密钥)
|
||||
# 生产环境请务必修改此密钥,并妥善保管
|
||||
ENCRYPTION_AES_KEY=your-32-byte-secret-key-here-12345678
|
||||
|
||||
# 哈希盐值(用于身份证哈希,增强安全性)
|
||||
# 生产环境请务必修改此盐值
|
||||
ENCRYPTION_HASH_SALT=your-hash-salt-here-change-in-production
|
||||
|
||||
# ============================================
|
||||
# 应用配置
|
||||
# ============================================
|
||||
|
||||
# 应用环境(development/production)
|
||||
APP_ENV=development
|
||||
|
||||
# 应用调试模式(true/false)
|
||||
APP_DEBUG=true
|
||||
|
||||
|
||||
# ============================================
|
||||
# 以下为:超级主机资源数据库
|
||||
# ============================================
|
||||
#主机标签数据库
|
||||
|
||||
TAG_MONGODB_DRIVER = "mongodb"
|
||||
TAG_MONGODB_DNS = mongodb://192.168.1.106:27017
|
||||
TAG_MONGODB_DATABASE = ckb
|
||||
TAG_MONGODB_USER = ckb
|
||||
TAG_MONGODB_AUTH = ckb
|
||||
TAG_MONGODB_PASSWORD = 123456
|
||||
|
||||
#主机同步KR数据库
|
||||
SYNC_MONGODB_HOST = 192.168.1.106
|
||||
SYNC_MONGODB_PORT = 27017
|
||||
SYNC_MONGODB_AUTH = KR
|
||||
SYNC_MONGODB_USER = KR
|
||||
SYNC_MONGODB_PASS = 123456
|
||||
|
||||
# ============================================
|
||||
# 以下为:爬虫抓取的业务数据库
|
||||
# ============================================
|
||||
|
||||
#卡若的数据库
|
||||
KR_MONGODB_HOST = 192.168.2.8
|
||||
KR_MONGODB_PORT = 27017
|
||||
KR_MONGODB_DATABASE = admin
|
||||
KR_MONGODB_USER = admin
|
||||
KR_MONGODB_PASSWORD = key123456
|
||||
KR_MONGODB_AUTH_SOURCE=admin
|
||||
|
||||
38
Moncter/start_debug.sh
Normal file
38
Moncter/start_debug.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 数据采集任务调试启动脚本(显示实时日志)
|
||||
# 使用方法: chmod +x start_debug.sh && ./start_debug.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "=================================================="
|
||||
echo " 数据采集任务 - 调试模式启动"
|
||||
echo " 实时显示所有日志输出"
|
||||
echo "=================================================="
|
||||
echo ""
|
||||
|
||||
# 检查 PHP
|
||||
if ! command -v php &> /dev/null; then
|
||||
echo "❌ 错误: 未找到 PHP,请先安装 PHP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ PHP 版本: $(php -v | head -n 1)"
|
||||
echo ""
|
||||
|
||||
# 停止已有进程
|
||||
if [ -f "runtime/webman.pid" ]; then
|
||||
echo "🛑 停止已运行的进程..."
|
||||
php start.php stop
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
# 以调试模式启动(不使用 daemon 模式,输出到终端)
|
||||
echo "🚀 启动 Workerman(调试模式)..."
|
||||
echo " 提示: 按 Ctrl+C 停止"
|
||||
echo "=================================================="
|
||||
echo ""
|
||||
|
||||
# 使用 start 而不是 start -d(daemon),这样输出会显示在终端
|
||||
php start.php start
|
||||
|
||||
@@ -29,9 +29,17 @@ if (empty(Worker::$eventLoopClass)) {
|
||||
}
|
||||
|
||||
set_error_handler(function ($level, $message, $file = '', $line = 0) {
|
||||
// 忽略 MongoDB Laravel 的废弃警告(E_USER_DEPRECATED = 16384)
|
||||
// 这些警告不影响功能,只是提示使用新的API
|
||||
if ($level === E_USER_DEPRECATED && strpos($message, 'Using "$collection" property is deprecated') !== false) {
|
||||
return true; // 忽略此警告
|
||||
}
|
||||
|
||||
if (error_reporting() & $level) {
|
||||
throw new ErrorException($message, 0, $level, $file, $line);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if ($worker) {
|
||||
|
||||
2492
Moncter/yarn.lock
Normal file
2492
Moncter/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
4
Touchkebao/.gitignore
vendored
4
Touchkebao/.gitignore
vendored
@@ -3,6 +3,4 @@ dist/
|
||||
build/
|
||||
yarn.lock
|
||||
.env
|
||||
.DS_Store
|
||||
.specstory/
|
||||
.cursorindexingignore
|
||||
.DS_Store
|
||||
Reference in New Issue
Block a user