初始化本地仓库
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\terminal;
|
||||
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\service\core\terminal\Terminal;
|
||||
use core\tool\Json;
|
||||
use core\tool\Sse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use support\annotation\Middleware;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class TerminalController
|
||||
{
|
||||
|
||||
#[OA\Get(
|
||||
path: "/terminal/config",
|
||||
summary: "获取终端配置",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[Permission(code: "terminal:config:read")]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false)]
|
||||
#[SimpleResponse(schema: [], example: [
|
||||
'enabled' => true,
|
||||
'npm_package_manager' => 'pnpm',
|
||||
'npm_registry' => 'npm',
|
||||
'composer_registry' => 'composer',
|
||||
'package_managers' => [
|
||||
'npm' => [
|
||||
'name' => 'NPM',
|
||||
'install' => 'npm install',
|
||||
'build' => 'npm run build',
|
||||
'check' => 'npm --version',
|
||||
],
|
||||
'cnpm' => [
|
||||
'name' => 'CNPM',
|
||||
'install' => 'cnpm install',
|
||||
'build' => 'cnpm run build',
|
||||
'check' => 'cnpm --version',
|
||||
],
|
||||
'pnpm' => [
|
||||
'name' => 'PNPM',
|
||||
'install' => 'pnpm install',
|
||||
'build' => 'pnpm run build',
|
||||
'check' => 'pnpm --version',
|
||||
],
|
||||
'yarn' => [
|
||||
'name' => 'YARN',
|
||||
'install' => 'yarn install',
|
||||
'build' => 'yarn build',
|
||||
'check' => 'yarn --version',
|
||||
],
|
||||
],
|
||||
'frontend_programs' => [
|
||||
'admin' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/admin/dist',
|
||||
'target_dir' => '{backend_root}/public/admin',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'web' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/web/.output/public',
|
||||
'target_dir' => '{backend_root}/public',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'h5' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/h5',
|
||||
'target_dir' => '{backend_root}/public/h5',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'app' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/app',
|
||||
'target_dir' => '{backend_root}/public/app',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'uni-app' => [
|
||||
'enabled' => true,
|
||||
'platforms' => [
|
||||
'h5' => [
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/h5',
|
||||
'target_dir' => '{backend_root}/public/uni-app/h5',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
],
|
||||
'mp-weixin' => [
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/mp-weixin',
|
||||
'target_dir' => '{backend_root}/public/uni-app/mp-weixin',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
],
|
||||
'app-plus' => [
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/app-plus',
|
||||
'target_dir' => '{backend_root}/public/uni-app/app-plus',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'default_platform' => 'h5',
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
])]
|
||||
public function config(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$config = [
|
||||
'enabled' => config('terminal.enabled', false),
|
||||
'npm_package_manager' => config('terminal.npm_package_manager', 'npm'),
|
||||
'npm_registry' => config('terminal.registries.npm.current', 'npm'),
|
||||
'composer_registry' => config('terminal.registries.composer.current', 'composer'),
|
||||
'package_managers' => config('terminal.package_managers', []),
|
||||
'frontend_programs' => config('terminal.frontend_programs', []),
|
||||
];
|
||||
|
||||
return Json::success('获取配置成功', $config);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: "/terminal/config",
|
||||
summary: "更新终端配置",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[Permission(code: "terminal:config:create")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function updateConfig(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
|
||||
// 读取当前配置
|
||||
$configFile = base_path() . '/config/terminal.php';
|
||||
$config = require $configFile;
|
||||
|
||||
// 更新包管理器配置
|
||||
if (isset($data['npm_package_manager'])) {
|
||||
$config['npm_package_manager'] = $data['npm_package_manager'];
|
||||
}
|
||||
|
||||
// 保存配置到文件
|
||||
$content = "<?php\n\nreturn " . $this->arrayToPhpConfig($config) . ";\n";
|
||||
file_put_contents($configFile, $content);
|
||||
|
||||
return Json::success('配置更新成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: "/terminal/commands",
|
||||
summary: "获取命令列表(带分组)",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[Permission(code: "terminal:config:commands")]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function commands(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$webConfig = config('terminal.web.command_groups', []);
|
||||
return Json::success('获取命令列表成功', $webConfig);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: "/terminal",
|
||||
summary: "执行命令(SSE方式)",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "command",
|
||||
description: "命令key",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "uuid",
|
||||
description: "会话UUID",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "extend",
|
||||
description: "扩展信息",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[Permission(code: "terminal:exec")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function exec(Request $request): void
|
||||
{
|
||||
$connection = $request->connection;
|
||||
$command = $request->input('command');
|
||||
$uuid = $request->input('uuid', '');
|
||||
$extend = $request->input('extend', '');
|
||||
|
||||
// 发送SSE响应头
|
||||
$connection->send(new Response(200, [
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Connection' => 'keep-alive',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Expose-Headers' => 'Content-Type',
|
||||
'X-Accel-Buffering' => 'no',
|
||||
], "\r\n"));
|
||||
|
||||
// 验证参数
|
||||
if (empty($command) || empty($uuid)) {
|
||||
$connection->send(Sse::error('参数错误:缺少command或uuid参数', null, $uuid));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$terminal = Terminal::create($uuid, $extend);
|
||||
|
||||
foreach ($terminal->exec($command) as $sseMessage) {
|
||||
$connection->send($sseMessage);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$connection->send(Sse::error('执行失败:' . $e->getMessage(), null, $uuid));
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: "/terminal/execute",
|
||||
summary: "执行命令(简单方式)",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "command_key",
|
||||
description: "命令key",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "variables",
|
||||
description: "命令变量",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "object"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "session_uuid",
|
||||
description: "会话UUID",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[Permission(code: "terminal:execute")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function execute(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$commandKey = $request->post('command_key');
|
||||
$variables = $request->post('variables', []);
|
||||
$sessionUuid = $request->post('session_uuid', '');
|
||||
|
||||
if (!$commandKey) {
|
||||
return Json::fail('命令不能为空');
|
||||
}
|
||||
|
||||
$terminal = Terminal::create($sessionUuid, '');
|
||||
$result = $terminal->executeSimple($commandKey, $variables, $sessionUuid);
|
||||
|
||||
return Json::success($result['message'], $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数组转换为PHP配置字符串
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $indent
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function arrayToPhpConfig(array $array, int $indent = 0): string
|
||||
{
|
||||
$spaces = str_repeat(' ', $indent);
|
||||
$result = "[\n";
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
$result .= $spaces . " ";
|
||||
|
||||
// 处理键名
|
||||
if (is_string($key)) {
|
||||
$result .= "'" . str_replace("'", "\\'", $key) . "' => ";
|
||||
} else {
|
||||
$result .= $key . " => ";
|
||||
}
|
||||
|
||||
// 处理值
|
||||
if (is_array($value)) {
|
||||
$result .= $this->arrayToPhpConfig($value, $indent + 1);
|
||||
} elseif (is_string($value)) {
|
||||
$result .= "'" . str_replace("'", "\\'", $value) . "'";
|
||||
} elseif (is_bool($value)) {
|
||||
$result .= $value ? 'true' : 'false';
|
||||
} elseif (is_null($value)) {
|
||||
$result .= 'null';
|
||||
} else {
|
||||
$result .= $value;
|
||||
}
|
||||
|
||||
$result .= ",\n";
|
||||
}
|
||||
|
||||
$result .= $spaces . "]";
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user