feat: enhance plugin management

- Add command support for plugin management
- Optimize plugin management page layout
- Add email copy functionality for users
- Convert payment methods and Telegram Bot to plugin system
This commit is contained in:
xboard
2025-07-26 18:49:58 +08:00
parent 02d853d46a
commit 58868268dd
56 changed files with 3677 additions and 1329 deletions
@@ -71,7 +71,6 @@ class ConfigController extends Controller
public function setTelegramWebhook(Request $request)
{
// 判断站点网址
$app_url = admin_setting('app_url');
if (blank($app_url))
return $this->fail([422, '请先设置站点网址']);
@@ -81,17 +80,14 @@ class ConfigController extends Controller
$telegramService = new TelegramService($request->input('telegram_bot_token'));
$telegramService->getMe();
$telegramService->setWebhook($hookUrl);
$telegramService->registerBotCommands();
return $this->success(true);
}
public function fetch(Request $request)
{
$key = $request->input('key');
// 构建配置数据映射
$configMappings = $this->getConfigMappings();
// 如果请求特定分组,直接返回
if ($key && isset($configMappings[$key])) {
return $this->success([$key => $configMappings[$key]]);
}
@@ -9,16 +9,18 @@ use App\Services\PaymentService;
use App\Utils\Helper;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class PaymentController extends Controller
{
public function getPaymentMethods()
{
$methods = [];
foreach (glob(base_path('app//Payments') . '/*.php') as $file) {
array_push($methods, pathinfo($file)['filename']);
}
return $this->success($methods);
$pluginMethods = PaymentService::getAllPaymentMethodNames();
$methods = array_merge($methods, $pluginMethods);
return $this->success(array_unique($methods));
}
public function fetch()
@@ -37,23 +39,29 @@ class PaymentController extends Controller
public function getPaymentForm(Request $request)
{
$paymentService = new PaymentService($request->input('payment'), $request->input('id'));
return $this->success(collect($paymentService->form())->values());
try {
$paymentService = new PaymentService($request->input('payment'), $request->input('id'));
return $this->success(collect($paymentService->form()));
} catch (\Exception $e) {
return $this->fail([400, '支付方式不存在或未启用']);
}
}
public function show(Request $request)
{
$payment = Payment::find($request->input('id'));
if (!$payment) return $this->fail([400202 ,'支付方式不存在']);
if (!$payment)
return $this->fail([400202, '支付方式不存在']);
$payment->enable = !$payment->enable;
if (!$payment->save()) return $this->fail([500 ,'保存失败']);
if (!$payment->save())
return $this->fail([500, '保存失败']);
return $this->success(true);
}
public function save(Request $request)
{
if (!admin_setting('app_url')) {
return $this->fail([400 ,'请在站点配置中配置站点地址']);
return $this->fail([400, '请在站点配置中配置站点地址']);
}
$params = $request->validate([
'name' => 'required',
@@ -73,18 +81,19 @@ class PaymentController extends Controller
]);
if ($request->input('id')) {
$payment = Payment::find($request->input('id'));
if (!$payment) return $this->fail([400202 ,'支付方式不存在']);
if (!$payment)
return $this->fail([400202, '支付方式不存在']);
try {
$payment->update($params);
} catch (\Exception $e) {
\Log::error($e);
return $this->fail([500 ,'保存失败']);
Log::error($e);
return $this->fail([500, '保存失败']);
}
return $this->success(true);
}
$params['uuid'] = Helper::randomChar(8);
if (!Payment::create($params)) {
return $this->fail([500 ,'保存失败']);
return $this->fail([500, '保存失败']);
}
return $this->success(true);
}
@@ -92,7 +101,8 @@ class PaymentController extends Controller
public function drop(Request $request)
{
$payment = Payment::find($request->input('id'));
if (!$payment) return $this->fail([400202 ,'支付方式不存在']);
if (!$payment)
return $this->fail([400202, '支付方式不存在']);
return $this->success($payment->delete());
}
@@ -105,7 +115,7 @@ class PaymentController extends Controller
'ids.required' => '参数有误',
'ids.array' => '参数有误'
]);
try{
try {
DB::beginTransaction();
foreach ($request->input('ids') as $k => $v) {
if (!Payment::find($v)->update(['sort' => $k + 1])) {
@@ -113,11 +123,11 @@ class PaymentController extends Controller
}
}
DB::commit();
}catch(\Exception $e){
} catch (\Exception $e) {
DB::rollBack();
return $this->fail([500 ,'保存失败']);
return $this->fail([500, '保存失败']);
}
return $this->success(true);
}
}
@@ -23,14 +23,43 @@ class PluginController extends Controller
$this->configService = $configService;
}
/**
* 获取所有插件类型
*/
public function types()
{
return response()->json([
'data' => [
[
'value' => Plugin::TYPE_FEATURE,
'label' => '功能',
'description' => '提供功能扩展的插件,如Telegram登录、邮件通知等',
'icon' => '🔧'
],
[
'value' => Plugin::TYPE_PAYMENT,
'label' => '支付方式',
'description' => '提供支付接口的插件,如支付宝、微信支付等',
'icon' => '💳'
]
]
]);
}
/**
* 获取插件列表
*/
public function index()
public function index(Request $request)
{
$installedPlugins = Plugin::get()
$type = $request->query('type');
$installedPlugins = Plugin::when($type, function($query) use ($type) {
return $query->byType($type);
})
->get()
->keyBy('code')
->toArray();
$pluginPath = base_path('plugins');
$plugins = [];
@@ -42,8 +71,14 @@ class PluginController extends Controller
if (File::exists($configFile)) {
$config = json_decode(File::get($configFile), true);
$code = $config['code'];
$pluginType = $config['type'] ?? Plugin::TYPE_FEATURE;
// 如果指定了类型,过滤插件
if ($type && $pluginType !== $type) {
continue;
}
$installed = isset($installedPlugins[$code]);
// 使用配置服务获取配置
$pluginConfig = $installed ? $this->configService->getConfig($code) : ($config['config'] ?? []);
$readmeFile = collect(['README.md', 'readme.md'])
->map(fn($f) => $directory . '/' . $f)
@@ -56,8 +91,11 @@ class PluginController extends Controller
'version' => $config['version'],
'description' => $config['description'],
'author' => $config['author'],
'type' => $pluginType,
'is_installed' => $installed,
'is_enabled' => $installed ? $installedPlugins[$code]['is_enabled'] : false,
'is_protected' => in_array($code, Plugin::PROTECTED_PLUGINS),
'can_be_deleted' => !in_array($code, Plugin::PROTECTED_PLUGINS),
'config' => $pluginConfig,
'readme' => $readmeContent,
];
@@ -236,8 +274,17 @@ class PluginController extends Controller
'code' => 'required|string'
]);
$code = $request->input('code');
// 检查是否为受保护的插件
if (in_array($code, Plugin::PROTECTED_PLUGINS)) {
return response()->json([
'message' => '该插件为系统默认插件,不允许删除'
], 403);
}
try {
$this->pluginManager->delete($request->input('code'));
$this->pluginManager->delete($code);
return response()->json([
'message' => '插件删除成功'
]);
@@ -164,7 +164,6 @@ class UserController extends Controller
$users = $userModel->orderBy('id', 'desc')
->paginate($pageSize, ['*'], 'page', $current);
/** @phpstan-ignore-next-line */
$users->getCollection()->transform(function ($user): array {
return self::transformUserData($user);
});