'/install/']); } if (is_file(public_path('index.html'))) { return new Response(302, ['Location' => '/index.html']); } return new Response(404, [], 'Not Found'); }); Route::get('/index.html', function () use ($installLockFile, $installCompleteMark, $installPageFile) { $needRedirect = is_file($installPageFile) && (!is_file($installLockFile) || @file_get_contents($installLockFile) !== $installCompleteMark); if ($needRedirect) { return new Response(302, ['Location' => '/install/']); } $file = public_path('index.html'); return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Not Found'); }); // ==================== 安装向导(静态页) ==================== // 已安装时访问 /install 重定向到应用,访问提示仅在终端显示 $installLockFileForInstall = public_path('install.lock'); $installCompleteMarkForInstall = 'install-end'; Route::get('/install', function () use ($installLockFileForInstall, $installCompleteMarkForInstall) { $installed = is_file($installLockFileForInstall) && @file_get_contents($installLockFileForInstall) === $installCompleteMarkForInstall; if ($installed && is_file(public_path('index.html'))) { return new Response(302, ['Location' => '/index.html']); } $file = public_path('install/index.html'); return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found'); }); Route::get('/install/', function () use ($installLockFileForInstall, $installCompleteMarkForInstall) { $installed = is_file($installLockFileForInstall) && @file_get_contents($installLockFileForInstall) === $installCompleteMarkForInstall; if ($installed && is_file(public_path('index.html'))) { return new Response(302, ['Location' => '/index.html']); } $file = public_path('install/index.html'); return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found'); }); Route::get('/install/index', function () use ($installLockFileForInstall, $installCompleteMarkForInstall) { $installed = is_file($installLockFileForInstall) && @file_get_contents($installLockFileForInstall) === $installCompleteMarkForInstall; if ($installed && is_file(public_path('index.html'))) { return new Response(302, ['Location' => '/index.html']); } $file = public_path('install/index.html'); return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found'); }); // ==================== API 路由 ==================== // api/index Route::get('/api/index/index', [\app\api\controller\Index::class, 'index']); // api/user(GET 获取配置,POST 登录/注册) Route::add(['GET', 'POST'], '/api/user/checkIn', [\app\api\controller\User::class, 'checkIn']); Route::post('/api/user/logout', [\app\api\controller\User::class, 'logout']); // api/install(安装流程多为 POST) Route::add(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'], '/api/install/terminal', [\app\api\controller\Install::class, 'terminal']); Route::post('/api/install/changePackageManager', [\app\api\controller\Install::class, 'changePackageManager']); Route::get('/api/install/envBaseCheck', [\app\api\controller\Install::class, 'envBaseCheck']); Route::add(['GET', 'POST'], '/api/install/envNpmCheck', [\app\api\controller\Install::class, 'envNpmCheck']); Route::post('/api/install/testDatabase', [\app\api\controller\Install::class, 'testDatabase']); Route::add(['GET', 'POST'], '/api/install/baseConfig', [\app\api\controller\Install::class, 'baseConfig']); Route::get('/api/install/accessUrls', [\app\api\controller\Install::class, 'accessUrls']); Route::post('/api/install/commandExecComplete', [\app\api\controller\Install::class, 'commandExecComplete']); Route::post('/api/install/manualInstall', [\app\api\controller\Install::class, 'manualInstall']); Route::post('/api/install/mvDist', [\app\api\controller\Install::class, 'mvDist']); // api/common Route::get('/api/common/captcha', [\app\api\controller\Common::class, 'captcha']); Route::get('/api/common/clickCaptcha', [\app\api\controller\Common::class, 'clickCaptcha']); Route::post('/api/common/checkClickCaptcha', [\app\api\controller\Common::class, 'checkClickCaptcha']); Route::post('/api/common/refreshToken', [\app\api\controller\Common::class, 'refreshToken']); // api/ajax Route::post('/api/ajax/upload', [\app\api\controller\Ajax::class, 'upload']); Route::get('/api/ajax/area', [\app\api\controller\Ajax::class, 'area']); Route::get('/api/ajax/buildSuffixSvg', [\app\api\controller\Ajax::class, 'buildSuffixSvg']); // api/account Route::get('/api/account/overview', [\app\api\controller\Account::class, 'overview']); Route::add(['GET', 'POST'], '/api/account/profile', [\app\api\controller\Account::class, 'profile']); Route::get('/api/account/verification', [\app\api\controller\Account::class, 'verification']); Route::post('/api/account/changeBind', [\app\api\controller\Account::class, 'changeBind']); Route::add(['GET', 'POST'], '/api/account/changePassword', [\app\api\controller\Account::class, 'changePassword']); Route::get('/api/account/integral', [\app\api\controller\Account::class, 'integral']); Route::get('/api/account/balance', [\app\api\controller\Account::class, 'balance']); Route::post('/api/account/retrievePassword', [\app\api\controller\Account::class, 'retrievePassword']); // api/ems Route::post('/api/ems/send', [\app\api\controller\Ems::class, 'send']); // ==================== Admin 路由 ==================== // Admin 多为 JSON API,前端可能用 GET 传参查列表、POST 提交表单,使用 any 确保兼容 // admin/index(小写) Route::get('/admin/index/index', [\app\admin\controller\Index::class, 'index']); Route::get('/admin/index/login', [\app\admin\controller\Index::class, 'login']); Route::post('/admin/index/login', [\app\admin\controller\Index::class, 'login']); Route::post('/admin/index/logout', [\app\admin\controller\Index::class, 'logout']); // 兼容前端请求 /admin/Index/*(首字母大写) Route::get('/admin/Index/index', [\app\admin\controller\Index::class, 'index']); Route::get('/admin/Index/login', [\app\admin\controller\Index::class, 'login']); Route::post('/admin/Index/login', [\app\admin\controller\Index::class, 'login']); Route::post('/admin/Index/logout', [\app\admin\controller\Index::class, 'logout']); // admin/dashboard Route::get('/admin/dashboard/index', [\app\admin\controller\Dashboard::class, 'index']); // 兼容前端请求 /admin/Dashboard/* Route::get('/admin/Dashboard/index', [\app\admin\controller\Dashboard::class, 'index']); // admin/module Route::get('/admin/module/index', [\app\admin\controller\Module::class, 'index']); Route::get('/admin/module/state', [\app\admin\controller\Module::class, 'state']); Route::post('/admin/module/install', [\app\admin\controller\Module::class, 'install']); Route::post('/admin/module/dependentInstallComplete', [\app\admin\controller\Module::class, 'dependentInstallComplete']); Route::post('/admin/module/changeState', [\app\admin\controller\Module::class, 'changeState']); Route::post('/admin/module/uninstall', [\app\admin\controller\Module::class, 'uninstall']); Route::post('/admin/module/upload', [\app\admin\controller\Module::class, 'upload']); // admin/ajax Route::post('/admin/ajax/upload', [\app\admin\controller\Ajax::class, 'upload']); Route::get('/admin/ajax/area', [\app\admin\controller\Ajax::class, 'area']); Route::get('/admin/ajax/buildSuffixSvg', [\app\admin\controller\Ajax::class, 'buildSuffixSvg']); Route::get('/admin/ajax/getDatabaseConnectionList', [\app\admin\controller\Ajax::class, 'getDatabaseConnectionList']); Route::get('/admin/ajax/getTablePk', [\app\admin\controller\Ajax::class, 'getTablePk']); Route::get('/admin/ajax/getTableList', [\app\admin\controller\Ajax::class, 'getTableList']); Route::get('/admin/ajax/getTableFieldList', [\app\admin\controller\Ajax::class, 'getTableFieldList']); Route::post('/admin/ajax/changeTerminalConfig', [\app\admin\controller\Ajax::class, 'changeTerminalConfig']); Route::post('/admin/ajax/clearCache', [\app\admin\controller\Ajax::class, 'clearCache']); Route::add(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'], '/admin/ajax/terminal', [\app\admin\controller\Ajax::class, 'terminal']); // admin/auth/admin Route::get('/admin/auth/admin/index', [\app\admin\controller\auth\Admin::class, 'index']); Route::post('/admin/auth/admin/add', [\app\admin\controller\auth\Admin::class, 'add']); Route::post('/admin/auth/admin/edit', [\app\admin\controller\auth\Admin::class, 'edit']); Route::post('/admin/auth/admin/del', [\app\admin\controller\auth\Admin::class, 'del']); // admin/auth/group Route::get('/admin/auth/group/index', [\app\admin\controller\auth\Group::class, 'index']); Route::post('/admin/auth/group/add', [\app\admin\controller\auth\Group::class, 'add']); Route::post('/admin/auth/group/edit', [\app\admin\controller\auth\Group::class, 'edit']); Route::post('/admin/auth/group/del', [\app\admin\controller\auth\Group::class, 'del']); Route::get('/admin/auth/group/select', [\app\admin\controller\auth\Group::class, 'select']); // admin/auth/rule Route::get('/admin/auth/rule/index', [\app\admin\controller\auth\Rule::class, 'index']); Route::post('/admin/auth/rule/add', [\app\admin\controller\auth\Rule::class, 'add']); Route::post('/admin/auth/rule/edit', [\app\admin\controller\auth\Rule::class, 'edit']); Route::post('/admin/auth/rule/del', [\app\admin\controller\auth\Rule::class, 'del']); Route::get('/admin/auth/rule/select', [\app\admin\controller\auth\Rule::class, 'select']); // admin/auth/adminLog(兼容 ThinkPHP 风格 /admin/auth.AdminLog/index) Route::get('/admin/auth/adminLog/index', [\app\admin\controller\auth\AdminLog::class, 'index']); Route::get('/admin/auth.AdminLog/index', [\app\admin\controller\auth\AdminLog::class, 'index']); // admin/user/user Route::get('/admin/user/user/index', [\app\admin\controller\user\User::class, 'index']); Route::post('/admin/user/user/add', [\app\admin\controller\user\User::class, 'add']); Route::post('/admin/user/user/edit', [\app\admin\controller\user\User::class, 'edit']); Route::get('/admin/user/user/select', [\app\admin\controller\user\User::class, 'select']); // admin/user/group Route::post('/admin/user/group/add', [\app\admin\controller\user\Group::class, 'add']); Route::post('/admin/user/group/edit', [\app\admin\controller\user\Group::class, 'edit']); // admin/user/rule Route::get('/admin/user/rule/index', [\app\admin\controller\user\Rule::class, 'index']); Route::post('/admin/user/rule/add', [\app\admin\controller\user\Rule::class, 'add']); Route::post('/admin/user/rule/edit', [\app\admin\controller\user\Rule::class, 'edit']); Route::post('/admin/user/rule/del', [\app\admin\controller\user\Rule::class, 'del']); Route::get('/admin/user/rule/select', [\app\admin\controller\user\Rule::class, 'select']); // admin/user/scoreLog Route::post('/admin/user/scoreLog/add', [\app\admin\controller\user\ScoreLog::class, 'add']); // admin/user/moneyLog Route::post('/admin/user/moneyLog/add', [\app\admin\controller\user\MoneyLog::class, 'add']); // admin/routine/config Route::get('/admin/routine/config/index', [\app\admin\controller\routine\Config::class, 'index']); Route::post('/admin/routine/config/edit', [\app\admin\controller\routine\Config::class, 'edit']); Route::post('/admin/routine/config/add', [\app\admin\controller\routine\Config::class, 'add']); Route::post('/admin/routine/config/sendTestMail', [\app\admin\controller\routine\Config::class, 'sendTestMail']); // admin/routine/adminInfo Route::get('/admin/routine/adminInfo/index', [\app\admin\controller\routine\AdminInfo::class, 'index']); Route::post('/admin/routine/adminInfo/edit', [\app\admin\controller\routine\AdminInfo::class, 'edit']); // admin/routine/attachment Route::post('/admin/routine/attachment/del', [\app\admin\controller\routine\Attachment::class, 'del']); // admin/crud/crud Route::post('/admin/crud/crud/generate', [\app\admin\controller\crud\Crud::class, 'generate']); Route::post('/admin/crud/crud/logStart', [\app\admin\controller\crud\Crud::class, 'logStart']); Route::post('/admin/crud/crud/delete', [\app\admin\controller\crud\Crud::class, 'delete']); Route::get('/admin/crud/crud/getFileData', [\app\admin\controller\crud\Crud::class, 'getFileData']); // 兼容 ThinkPHP 风格 URL:/admin/crud.Crud/getFileData Route::get('/admin/crud.Crud/getFileData', [\app\admin\controller\crud\Crud::class, 'getFileData']); Route::get('/admin/crud/crud/checkCrudLog', [\app\admin\controller\crud\Crud::class, 'checkCrudLog']); Route::post('/admin/crud/crud/parseFieldData', [\app\admin\controller\crud\Crud::class, 'parseFieldData']); Route::post('/admin/crud/crud/generateCheck', [\app\admin\controller\crud\Crud::class, 'generateCheck']); Route::post('/admin/crud/crud/uploadCompleted', [\app\admin\controller\crud\Crud::class, 'uploadCompleted']); // admin/crud/log Route::get('/admin/crud/log/index', [\app\admin\controller\crud\Log::class, 'index']); // admin/security/sensitiveData Route::get('/admin/security/sensitiveData/index', [\app\admin\controller\security\SensitiveData::class, 'index']); Route::add(['GET', 'POST'], '/admin/security/sensitiveData/add', [\app\admin\controller\security\SensitiveData::class, 'add']); Route::add(['GET', 'POST'], '/admin/security/sensitiveData/edit', [\app\admin\controller\security\SensitiveData::class, 'edit']); Route::post('/admin/security/sensitiveData/del', [\app\admin\controller\security\SensitiveData::class, 'del']); // admin/security/sensitiveDataLog Route::get('/admin/security/sensitiveDataLog/index', [\app\admin\controller\security\SensitiveDataLog::class, 'index']); Route::get('/admin/security/sensitiveDataLog/info', [\app\admin\controller\security\SensitiveDataLog::class, 'info']); Route::post('/admin/security/sensitiveDataLog/rollback', [\app\admin\controller\security\SensitiveDataLog::class, 'rollback']); // admin/security/dataRecycle Route::get('/admin/security/dataRecycle/index', [\app\admin\controller\security\DataRecycle::class, 'index']); Route::add(['GET', 'POST'], '/admin/security/dataRecycle/add', [\app\admin\controller\security\DataRecycle::class, 'add']); Route::add(['GET', 'POST'], '/admin/security/dataRecycle/edit', [\app\admin\controller\security\DataRecycle::class, 'edit']); Route::post('/admin/security/dataRecycle/del', [\app\admin\controller\security\DataRecycle::class, 'del']); // admin/security/dataRecycleLog Route::get('/admin/security/dataRecycleLog/index', [\app\admin\controller\security\DataRecycleLog::class, 'index']); Route::post('/admin/security/dataRecycleLog/restore', [\app\admin\controller\security\DataRecycleLog::class, 'restore']); Route::get('/admin/security/dataRecycleLog/info', [\app\admin\controller\security\DataRecycleLog::class, 'info']); // ==================== 显式路由(优先级高,避免动态路由误匹配) ==================== Route::add(['GET', 'POST', 'HEAD'], '/admin/game.User/defaultWeightPresets', [\app\admin\controller\game\User::class, 'defaultWeightPresets']); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.User/defaultWeightByChannel', [\app\admin\controller\game\User::class, 'defaultWeightByChannel']); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.user/defaultWeightPresets', [\app\admin\controller\game\User::class, 'defaultWeightPresets']); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.user/defaultWeightByChannel', [\app\admin\controller\game\User::class, 'defaultWeightByChannel']); // 游戏渠道:删除前统计关联数据(显式路由,避免动态路由 404) Route::add(['GET', 'POST', 'HEAD'], '/admin/game.Channel/deleteRelatedCounts', [\app\admin\controller\game\Channel::class, 'deleteRelatedCounts']); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.channel/deleteRelatedCounts', [\app\admin\controller\game\Channel::class, 'deleteRelatedCounts']); // ==================== 兼容 ThinkPHP 风格 URL(module.Controller/action) ==================== // 前端使用 /admin/user.Rule/index 格式,需转换为控制器调用 Route::add( ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'], '/admin/{controllerPart:[a-zA-Z]+\\.[a-zA-Z0-9]+}/{action:[^/]+}', function (\Webman\Http\Request $request, string $controllerPart, string $action) { $pos = strpos($controllerPart, '.'); if ($pos === false) { return new Response(404, ['Content-Type' => 'application/json'], json_encode(['code' => 404, 'msg' => '404 Not Found', 'data' => []], JSON_UNESCAPED_UNICODE)); } $module = substr($controllerPart, 0, $pos); $controller = substr($controllerPart, $pos + 1); // game.user / game.User 等:小写控制器名需解析为 User.php(PSR-4 类名 StudlyCase) $class = null; $candidates = array_unique([ $controller, ucfirst($controller), ucfirst(strtolower($controller)), ]); foreach ($candidates as $base) { $tryClass = '\\app\\admin\\controller\\' . strtolower($module) . '\\' . $base; if (class_exists($tryClass)) { $class = $tryClass; break; } } if ($class === null) { return new Response(404, ['Content-Type' => 'application/json'], json_encode(['code' => 404, 'msg' => '404 Not Found', 'data' => []], JSON_UNESCAPED_UNICODE)); } if (!method_exists($class, $action)) { return new Response(404, ['Content-Type' => 'application/json'], json_encode(['code' => 404, 'msg' => '404 Not Found', 'data' => []], JSON_UNESCAPED_UNICODE)); } // 设置 controller 供 get_controller_path、权限校验等使用 $request->controller = $class; try { $instance = new $class(); return $instance->$action($request); } catch (\Throwable $e) { return new Response(500, ['Content-Type' => 'application/json'], json_encode([ 'code' => 0, 'msg' => $e->getMessage(), 'time' => time(), 'data' => null, ], JSON_UNESCAPED_UNICODE)); } } ); // 兜底:closure 显式调用,避免路由绑定在某些情况下仍落到 404 Route::add(['GET', 'POST', 'HEAD'], '/admin/game.User/defaultWeightByChannel/', function (\Webman\Http\Request $request) { return (new \app\admin\controller\game\User())->defaultWeightByChannel($request); }); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.user/defaultWeightByChannel/', function (\Webman\Http\Request $request) { return (new \app\admin\controller\game\User())->defaultWeightByChannel($request); }); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.User/defaultWeightPresets/', function (\Webman\Http\Request $request) { return (new \app\admin\controller\game\User())->defaultWeightPresets($request); }); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.user/defaultWeightPresets/', function (\Webman\Http\Request $request) { return (new \app\admin\controller\game\User())->defaultWeightPresets($request); }); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.Channel/deleteRelatedCounts/', function (\Webman\Http\Request $request) { return (new \app\admin\controller\game\Channel())->deleteRelatedCounts($request); }); Route::add(['GET', 'POST', 'HEAD'], '/admin/game.channel/deleteRelatedCounts/', function (\Webman\Http\Request $request) { return (new \app\admin\controller\game\Channel())->deleteRelatedCounts($request); }); // ==================== CORS 预检(OPTIONS) ==================== // 放在最后注册;显式加上前端会请求的路径,再加固通配 Route::add('OPTIONS', '/api/index/index', [\app\common\middleware\AllowCrossDomain::class, 'optionsResponse']); Route::add('OPTIONS', '/api/{path:.+}', [\app\common\middleware\AllowCrossDomain::class, 'optionsResponse']); Route::add('OPTIONS', '/admin/{path:.+}', [\app\common\middleware\AllowCrossDomain::class, 'optionsResponse']);