项目初始化

This commit is contained in:
2026-03-18 17:19:03 +08:00
commit ac6079b9ff
602 changed files with 58291 additions and 0 deletions

26
config/app.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
use support\Request;
return [
'debug' => true,
'error_reporting' => E_ALL,
'default_timezone' => 'Asia/Shanghai',
'request_class' => Request::class,
'public_path' => base_path() . DIRECTORY_SEPARATOR . 'public',
'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime',
'controller_suffix' => 'Controller',
'controller_reuse' => false,
];

21
config/autoload.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
'files' => [
base_path() . '/app/functions.php',
base_path() . '/support/Request.php',
base_path() . '/support/Response.php',
]
];

20
config/bootstrap.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
support\bootstrap\Session::class,
Webman\ThinkOrm\ThinkOrm::class,
support\bootstrap\ValidateInit::class,
support\bootstrap\ModuleInit::class,
];

88
config/buildadmin.php Normal file
View File

@@ -0,0 +1,88 @@
<?php
// +----------------------------------------------------------------------
// | BuildAdmin设置
// +----------------------------------------------------------------------
return [
// 允许跨域访问的域名(* 表示任意;开发可用 *,生产建议填具体域名)
'cors_request_domain' => '*',
// 是否开启会员登录验证码
'user_login_captcha' => true,
// 是否开启管理员登录验证码
'admin_login_captcha' => true,
// 会员登录失败可重试次数,false则无限
'user_login_retry' => 10,
// 管理员登录失败可重试次数,false则无限
'admin_login_retry' => 10,
// 开启管理员单处登录它处失效
'admin_sso' => false,
// 开启会员单处登录它处失效
'user_sso' => false,
// 会员登录态保持时间非刷新token3天
'user_token_keep_time' => 60 * 60 * 24 * 3,
// 管理员登录态保持时间非刷新token3天
'admin_token_keep_time' => 60 * 60 * 24 * 3,
// 开启前台会员中心
'open_member_center' => true,
// 模块纯净安装(安装时移动模块文件而不是复制)
'module_pure_install' => true,
// 点选验证码配置
'click_captcha' => [
// 模式:text=文字,icon=图标(若只有icon则适用于国际化站点)
'mode' => ['text', 'icon'],
// 长度
'length' => 2,
// 混淆点长度
'confuse_length' => 2,
// 自定义字体路径(当项目字体不存在且系统回退失败时可指定,如: C:\Windows\Fonts\simhei.ttf
'font_path' => '',
],
// 代理服务器IPRequest 类将尝试获取这些代理服务器发送过来的真实IP
'proxy_server_ip' => [],
// Token 配置
'token' => [
// 默认驱动方式
'default' => 'mysql',
// 加密key
'key' => 'L1iYVS0PChKA9pjcFdmOGb4zfDIHo5xw',
// 加密方式
'algo' => 'ripemd160',
// 驱动
'stores' => [
'mysql' => [
'type' => 'Mysql',
// 留空表示使用默认的 Mysql 数据库,也可以填写其他数据库连接配置的`name`
'name' => '',
// 存储token的表名
'table' => 'token',
// 默认 token 有效时间
'expire' => 2592000,
],
'redis' => [
'type' => 'Redis',
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
// Db索引非 0 以避免数据被意外清理
'select' => 1,
'timeout' => 0,
// 默认 token 有效时间
'expire' => 2592000,
'persistent' => false,
'prefix' => 'tk:',
],
]
],
// 自动写入管理员操作日志
'auto_write_admin_log' => true,
// 缺省头像图片路径
'default_avatar' => '/static/images/avatar.png',
// 内容分发网络URL末尾不带`/`
'cdn_url' => '',
// 内容分发网络URL参数将自动添加 `?`,之后拼接到 cdn_url 的结尾(例如 `imageMogr2/format/heif`
'cdn_url_params' => '',
// 版本号
'version' => 'v2.3.6',
// 中心接口地址(用于请求模块市场的数据等用途)
'api_url' => 'https://api.buildadmin.com',
];

37
config/cache.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
$env = function (string $dotKey, $default = null) {
$upperKey = strtoupper(str_replace('.', '_', $dotKey));
$value = env($dotKey, null);
if ($value === null) {
$value = env($upperKey, $default);
}
return $value ?? $default;
};
return [
// 默认缓存驱动
'default' => $env('cache.driver', 'file'),
// 缓存连接方式配置
'stores' => [
'file' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => base_path() . DIRECTORY_SEPARATOR . 'runtime' . DIRECTORY_SEPARATOR . 'cache',
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制 例如 ['serialize', 'unserialize']
'serialize' => [],
],
// 更多的缓存连接
],
];

15
config/container.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return new Webman\Container;

38
config/database.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
$env = function (string $dotKey, $default = null) {
$upperKey = strtoupper(str_replace('.', '_', $dotKey));
$value = env($dotKey, null);
if ($value === null) {
$value = env($upperKey, $default);
}
return $value ?? $default;
};
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => $env('database.hostname', '127.0.0.1'),
'port' => $env('database.hostport', '3306'),
'database' => $env('database.database', 'dafuweng-buildadmin'),
'username' => $env('database.username', 'dafuweng-buildadmin'),
'password' => $env('database.password', '123456'),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
'options' => [
PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers.
],
'pool' => [
'max_connections' => 5,
'min_connections' => 1,
'wait_timeout' => 3,
'idle_timeout' => 60,
'heartbeat_interval' => 50,
],
],
],
];

15
config/dependence.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [];

11
config/events.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
/**
* 事件监听BuildAdmin 兼容 Event::trigger
*/
return [
'listen' => [
'backendInit' => [
\app\common\event\Security::class, // 数据回收、敏感数据记录
],
],
];

17
config/exception.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
'' => support\exception\Handler::class,
];

20
config/filesystem.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
/**
* 文件系统配置BuildAdmin Upload 所需)
*/
return [
'default' => env('filesystem.driver', 'local'),
'disks' => [
'local' => [
'type' => 'local',
'root' => rtrim(runtime_path(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'storage',
],
'public' => [
'type' => 'local',
'root' => rtrim(base_path(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'public',
'url' => '/storage',
'visibility' => 'public',
],
],
];

8
config/lang.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
/**
* 多语言设置BuildAdmin 兼容)
*/
return [
'default_lang' => env('LANG_DEFAULT_LANG', 'zh-cn'),
'allow_lang_list' => ['zh-cn', 'en'],
];

32
config/log.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
'default' => [
'handlers' => [
[
'class' => Monolog\Handler\RotatingFileHandler::class,
'constructor' => [
runtime_path() . '/logs/webman.log',
7, //$maxFiles
Monolog\Logger::DEBUG,
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [null, 'Y-m-d H:i:s', true],
],
]
],
],
];

26
config/middleware.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* 中间件配置
* '' 为全局中间件,按顺序执行
* 原 ThinkPHP api/admin 中间件迁移至此
*/
return [
'' => [
\app\common\middleware\AllowCrossDomain::class,
\app\common\middleware\LoadLangPack::class,
\app\common\middleware\AdminLog::class,
],
];

View File

@@ -0,0 +1,28 @@
<?php
return [
'enable' => true,
'build_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
'phar_filename' => 'webman.phar',
'phar_format' => Phar::PHAR, // Phar archive format: Phar::PHAR, Phar::TAR, Phar::ZIP
'phar_compression' => Phar::NONE, // Compression method for Phar archive: Phar::NONE, Phar::GZ, Phar::BZ2
'bin_filename' => 'webman.bin',
'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
'exclude_pattern' => '#^(?!.*(composer.json|/.github/|/.idea/|/.git/|/.setting/|/runtime/|/vendor-bin/|/build/|/vendor/webman/admin/))(.*)$#',
'exclude_files' => [
'.env', 'LICENSE', 'composer.json', 'composer.lock', 'start.php', 'webman.phar', 'webman.bin'
],
'custom_ini' => '
memory_limit = 256M
',
];

View File

@@ -0,0 +1,8 @@
<?php
use support\validation\ValidationException;
return [
'enable' => true,
'exception' => ValidationException::class,
];

View File

@@ -0,0 +1,7 @@
<?php
use Webman\Validation\Command\MakeValidatorCommand;
return [
MakeValidatorCommand::class
];

View File

@@ -0,0 +1,9 @@
<?php
use Webman\Validation\Middleware;
return [
'@' => [
Middleware::class,
],
];

62
config/process.php Normal file
View File

@@ -0,0 +1,62 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
use support\Log;
use support\Request;
use app\process\Http;
global $argv;
return [
'webman' => [
'handler' => Http::class,
'listen' => 'http://0.0.0.0:8787',
'count' => cpu_count() * 4,
'user' => '',
'group' => '',
'reusePort' => false,
'eventLoop' => '',
'context' => [],
'constructor' => [
'requestClass' => Request::class,
'logger' => Log::channel('default'),
'appPath' => app_path(),
'publicPath' => public_path()
]
],
// File update detection and automatic reload
'monitor' => [
'handler' => app\process\Monitor::class,
'reloadable' => false,
'constructor' => [
// Monitor these directories
'monitorDir' => array_merge([
app_path(),
config_path(),
base_path() . '/process',
base_path() . '/support',
base_path() . '/resource',
base_path() . '/.env',
], glob(base_path() . '/plugin/*/app'), glob(base_path() . '/plugin/*/config'), glob(base_path() . '/plugin/*/api')),
// Files with these suffixes will be monitored
'monitorExtensions' => [
'php', 'html', 'htm', 'env'
],
'options' => [
'enable_file_monitor' => !in_array('-d', $argv) && DIRECTORY_SEPARATOR === '/',
'enable_memory_monitor' => DIRECTORY_SEPARATOR === '/',
]
]
]
];

29
config/redis.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
'default' => [
'password' => '',
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
'pool' => [
'max_connections' => 5,
'min_connections' => 1,
'wait_timeout' => 3,
'idle_timeout' => 60,
'heartbeat_interval' => 50,
],
]
];

287
config/route.php Normal file
View File

@@ -0,0 +1,287 @@
<?php
/**
* BuildAdmin Webman 路由
* 根据 ThinkPHP pathinfo 规则(应用/控制器/方法)生成
* GET=只读 POST=写入 ANY=兼容多种请求
*/
use Webman\Route;
use support\Response;
// ==================== 未安装时根路径重定向(迁移自 public/index.php ====================
// 当 install.lock 不存在或未完成安装时,访问 / 或 /index.html 重定向到安装页
$installLockFile = public_path('install.lock');
$installCompleteMark = 'install-end';
$installPageFile = public_path('install/index.html');
Route::get('/', 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/']);
}
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/userGET 获取配置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
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']);
// ==================== 兼容 ThinkPHP 风格 URLmodule.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);
$class = '\\app\\admin\\controller\\' . strtolower($module) . '\\' . $controller;
if (!class_exists($class)) {
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));
}
}
);
// ==================== 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']);

23
config/server.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
return [
'event_loop' => '',
'stop_timeout' => 2,
'pid_file' => runtime_path() . '/webman.pid',
'status_file' => runtime_path() . '/webman.status',
'stdout_file' => runtime_path() . '/logs/stdout.log',
'log_file' => runtime_path() . '/logs/workerman.log',
'max_package_size' => 10 * 1024 * 1024
];

65
config/session.php Normal file
View File

@@ -0,0 +1,65 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
use Webman\Session\FileSessionHandler;
use Webman\Session\RedisSessionHandler;
use Webman\Session\RedisClusterSessionHandler;
return [
'type' => 'file', // or redis or redis_cluster
'handler' => FileSessionHandler::class,
'config' => [
'file' => [
'save_path' => runtime_path() . '/sessions',
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
'auth' => '',
'timeout' => 2,
'database' => '',
'prefix' => 'redis_session_',
],
'redis_cluster' => [
'host' => ['127.0.0.1:7000', '127.0.0.1:7001', '127.0.0.1:7001'],
'timeout' => 2,
'auth' => '',
'prefix' => 'redis_session_',
]
],
'session_name' => 'PHPSID',
'auto_update_timestamp' => false,
'lifetime' => 7*24*60*60,
'cookie_lifetime' => 365*24*60*60,
'cookie_path' => '/',
'domain' => '',
'http_only' => true,
'secure' => false,
'same_site' => '',
'gc_probability' => [1, 1000],
];

23
config/static.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Static file settings
*/
return [
'enable' => true,
'middleware' => [ // Static file Middleware
//app\middleware\StaticFile::class,
],
];

83
config/terminal.php Normal file
View File

@@ -0,0 +1,83 @@
<?php
// +----------------------------------------------------------------------
// | BuildAdmin - WEB终端配置
// | Webman 迁移migrate 命令需根据实际迁移工具调整
// +----------------------------------------------------------------------
return [
'npm_package_manager' => 'pnpm',
'commands' => [
'migrate' => [
'run' => [
'cwd' => '',
'command' => 'php vendor/bin/phinx migrate',
'notes' => 'Start the database migration'
],
'rollback' => ['cwd' => '', 'command' => 'php vendor/bin/phinx rollback'],
'breakpoint' => ['cwd' => '', 'command' => 'php vendor/bin/phinx breakpoint'],
],
'install' => [
'cnpm' => 'npm install cnpm -g --registry=https://registry.npmmirror.com',
'yarn' => 'npm install -g yarn',
'pnpm' => 'npm install -g pnpm',
'ni' => 'npm install -g @antfu/ni',
],
'version' => [
'npm' => 'npm -v',
'cnpm' => 'cnpm -v',
'yarn' => 'yarn -v',
'pnpm' => 'pnpm -v',
'node' => 'node -v',
],
'test' => [
'npm' => ['cwd' => 'public/npm-install-test', 'command' => 'npm install'],
'cnpm' => ['cwd' => 'public/npm-install-test', 'command' => 'cnpm install'],
'yarn' => ['cwd' => 'public/npm-install-test', 'command' => 'yarn install'],
'pnpm' => ['cwd' => 'public/npm-install-test', 'command' => 'pnpm install'],
'ni' => ['cwd' => 'public/npm-install-test', 'command' => 'ni install'],
],
'web-install' => [
'npm' => ['cwd' => 'web', 'command' => 'npm install'],
'cnpm' => ['cwd' => 'web', 'command' => 'cnpm install'],
'yarn' => ['cwd' => 'web', 'command' => 'yarn install'],
'pnpm' => ['cwd' => 'web', 'command' => 'pnpm install'],
'ni' => ['cwd' => 'web', 'command' => 'ni install'],
],
'nuxt-install' => [
'npm' => ['cwd' => 'web-nuxt', 'command' => 'npm install'],
'cnpm' => ['cwd' => 'web-nuxt', 'command' => 'cnpm install'],
'yarn' => ['cwd' => 'web-nuxt', 'command' => 'yarn install'],
'pnpm' => ['cwd' => 'web-nuxt', 'command' => 'pnpm install'],
'ni' => ['cwd' => 'web-nuxt', 'command' => 'ni install'],
],
'web-build' => [
'npm' => ['cwd' => 'web', 'command' => 'npm run build', 'notes' => 'Start executing the build command of the web project'],
'cnpm' => ['cwd' => 'web', 'command' => 'cnpm run build', 'notes' => 'Start executing the build command of the web project'],
'yarn' => ['cwd' => 'web', 'command' => 'yarn run build', 'notes' => 'Start executing the build command of the web project'],
'pnpm' => ['cwd' => 'web', 'command' => 'pnpm run build', 'notes' => 'Start executing the build command of the web project'],
'ni' => ['cwd' => 'web', 'command' => 'nr build', 'notes' => 'Start executing the build command of the web project'],
],
'set-npm-registry' => [
'npm' => 'npm config set registry https://registry.npmjs.org/ && npm config get registry',
'taobao' => 'npm config set registry https://registry.npmmirror.com/ && npm config get registry',
'tencent' => 'npm config set registry https://mirrors.cloud.tencent.com/npm/ && npm config get registry'
],
'set-composer-registry' => [
'composer' => 'composer config --unset repos.packagist',
'aliyun' => 'composer config -g repos.packagist composer https://mirrors.aliyun.com/composer/',
'tencent' => 'composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/',
'huawei' => 'composer config -g repos.packagist composer https://mirrors.huaweicloud.com/repository/php/',
'kkame' => 'composer config -g repos.packagist composer https://packagist.kr',
],
'npx' => [
'prettier' => ['cwd' => 'web', 'command' => 'npx prettier --write %s', 'notes' => 'Start formatting the web project code'],
],
'composer' => [
'update' => ['cwd' => '', 'command' => 'composer update --no-interaction', 'notes' => 'Start installing the composer dependencies']
],
'ping' => [
'baidu' => 'ping baidu.com',
'localhost' => 'ping 127.0.0.1 -n 6',
]
],
];

95
config/thinkorm.php Normal file
View File

@@ -0,0 +1,95 @@
<?php
/**
* ThinkORM 数据库配置
* 从 config/database.php 迁移
*
* .env 支持两种格式(二选一):
* 1. BuildAdmin 格式database.hostname、database.database 等(需 env 支持点号)
* 2. 标准格式DATABASE_HOSTNAME、DATABASE_DATABASE 等
*/
$env = function (string $dotKey, $default = null) {
$upperKey = strtoupper(str_replace('.', '_', $dotKey));
$value = env($dotKey, null);
if ($value === null) {
$value = env($upperKey, $default);
}
return $value ?? $default;
};
return [
// 默认使用的数据库连接配置
'default' => $env('database.driver', 'mysql'),
// 自定义时间查询规则
'time_query_rule' => [],
// 自动写入时间戳字段
'auto_timestamp' => true,
// 时间字段取出后的默认时间格式
'datetime_format' => false,
// 时间字段配置 配置格式create_time,update_time
'datetime_field' => '',
// 数据库连接配置信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => $env('database.type', 'mysql'),
// 服务器地址
'hostname' => $env('database.hostname', '127.0.0.1'),
// 数据库名(与 database.php / .env 一致)
'database' => $env('database.database', 'webman-buildadmin-mall'),
// 用户名(与 .env DATABASE_USERNAME 一致,默认勿用 root 以免与本机 MySQL 不符)
'username' => $env('database.username', 'webman-buildadmin-mall'),
// 密码(与 .env DATABASE_PASSWORD 一致)
'password' => $env('database.password', '123456'),
// 端口
'hostport' => $env('database.hostport', '3306'),
// 数据库连接参数MYSQL_ATTR_USE_BUFFERED_QUERY 避免 "Cannot execute queries while other unbuffered queries are active"
'params' => [
\PDO::ATTR_TIMEOUT => 3,
\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
],
// 数据库编码默认采用 utf8mb4
'charset' => $env('database.charset', 'utf8mb4'),
// 数据库表前缀
'prefix' => $env('database.prefix', ''),
// 数据库部署方式:0 集中式,1 分布式(主从)
'deploy' => 0,
// 数据库读写是否分离
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => true,
// 监听SQL调试用
'trigger_sql' => $env('app_debug', false),
// 开启字段缓存
'fields_cache' => false,
// 连接池配置Webman 常驻内存模式必需)
'pool' => [
'max_connections' => 5,
'min_connections' => 1,
'wait_timeout' => 3,
'idle_timeout' => 60,
'heartbeat_interval' => 50,
],
],
],
// 自定义分页类
'paginator' => '',
// 迁移表名TableManager/Phinx 使用)
'migration_table' => 'migrations',
];

29
config/translation.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Multilingual configuration
*/
return [
// Default language
'locale' => 'zh_CN',
// Fallback language
'fallback_locale' => ['zh_CN', 'en'],
// Folder where language files are stored含 BuildAdmin app 语言包)
'path' => [
base_path() . '/resource/translations',
base_path() . '/app/api/lang',
base_path() . '/app/admin/lang',
],
];

21
config/upload.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
// +----------------------------------------------------------------------
// | BuildAdmin上传设置
// +----------------------------------------------------------------------
return [
// 最大上传
'max_size' => '10mb',
// 文件保存格式化方法:topic=存储子目录,fileName=文件名前15个字符
'save_name' => '/storage/{topic}/{year}{mon}{day}/{fileName}{fileSha1}{.suffix}',
/**
* 上传文件的后缀和 MIME类型 白名单
* 0. 永远使用最少配置
* 1. 此处不支持通配符
* 2. 千万不要允许 php,php5,.htaccess,.user.ini 等可执行或配置文件
* 3. 允许 pdf,ppt,docx 等可能含有脚本的文件时,请先从服务器配置此类文件直接下载而不是预览
*/
'allowed_suffixes' => 'jpg,png,bmp,jpeg,gif,webp,zip,rar,wav,mp4,mp3',
'allowed_mime_types' => [],
];

22
config/view.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
use support\view\Raw;
use support\view\Twig;
use support\view\Blade;
use support\view\ThinkPHP;
return [
'handler' => Raw::class
];