mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 17:17:13 +08:00
特性(网站):新增备份功能及问题修复
This commit is contained in:
46
CHANGELOG.md
Normal file
46
CHANGELOG.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# 更新日志
|
||||
|
||||
所有重要的更改都将在此文件中记录。
|
||||
|
||||
|
||||
## [20221203] - 常规更新
|
||||
|
||||
- 修复禁用Ping不生效的问题
|
||||
- 修复网站设置PHP版本未赋值的问题
|
||||
- 新增网站目录备份功能
|
||||
- 新增面板多用户登录功能
|
||||
- 实装网站运行状态设置功能
|
||||
- 实装网站配置文件重置功能
|
||||
- 前端多处优化
|
||||
|
||||
## [20221202] - 常规更新
|
||||
|
||||
- 修复网站添加数据库不能为空的问题
|
||||
- 校验网站目录必须以/开头
|
||||
- 修复网站名可以编辑的问题
|
||||
- 新增面板API开关
|
||||
- 新增计划任务模块
|
||||
- 安装脚本优化,提高在不同地区下的安装成功率
|
||||
|
||||
## [20221201] - 首版发布
|
||||
|
||||
- 修复了二测时发现的一些问题
|
||||
- 首发于Hostloc,感谢各位mjj大佬的支持。
|
||||
|
||||
## [20221130] - 内部二测
|
||||
|
||||
- 内部二测
|
||||
- 修复了一测发现的问题
|
||||
- 新增了一些插件,基本功能已经完善
|
||||
|
||||
## [20221121] - 内部一测
|
||||
|
||||
- 内部一测
|
||||
|
||||
## 2022-10 - 2022-11
|
||||
|
||||
- 重构版本开始开发
|
||||
|
||||
## 2022-07 - 2022-08
|
||||
|
||||
- 项目启动、早期开发
|
||||
@@ -13,6 +13,8 @@
|
||||
| RockyLinux | 8 |
|
||||
| AlmaLinux | 9 |
|
||||
| AlmaLinux | 8 |
|
||||
| 其他RHEL发行版 | 8 |
|
||||
| 其他RHEL发行版 | 9 |
|
||||
|
||||
广告: [`WeAvatar` —统一头像服务](https://weavatar.com)
|
||||
|
||||
|
||||
@@ -286,7 +286,10 @@ class PluginsController extends Controller
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
Plugin::query()->where('slug', $slug)->update(['show' => $show]);
|
||||
Plugin::query()->where('slug', $slug)->updateOrInsert(
|
||||
['slug' => $slug],
|
||||
['show' => $show]
|
||||
);
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
$res['data'] = '设置成功';
|
||||
|
||||
@@ -34,7 +34,13 @@ class SettingsController extends Controller
|
||||
// 从nginx配置文件中获取面板端口
|
||||
$nginxConf = file_get_contents('/www/server/nginx/conf/nginx.conf');
|
||||
preg_match('/listen\s+(\d+)/', $nginxConf, $matches);
|
||||
if (!isset($matches[1])) {
|
||||
$res['code'] = 1;
|
||||
$res['msg'] = '获取面板端口失败,请检查nginx主配置文件';
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
// API
|
||||
$api = 0;
|
||||
$apiToken = '';
|
||||
if (isset($settingArr['api']) && $settingArr['api'] == 1) {
|
||||
@@ -42,11 +48,12 @@ class SettingsController extends Controller
|
||||
$apiToken = $settingArr['api_token'] ?? '';
|
||||
}
|
||||
|
||||
if (!isset($matches[1])) {
|
||||
$res['code'] = 1;
|
||||
$res['msg'] = '获取面板端口失败,请检查nginx主配置文件';
|
||||
return response()->json($res);
|
||||
// 多设备登录
|
||||
$multiLogin = 0;
|
||||
if (isset($settingArr['multi_login']) && $settingArr['multi_login'] == 1) {
|
||||
$multiLogin = 1;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'name' => $settingArr['name'],
|
||||
'username' => $request->user()->username,
|
||||
@@ -54,6 +61,7 @@ class SettingsController extends Controller
|
||||
'port' => $matches[1],
|
||||
'api' => $api,
|
||||
'api_token' => $apiToken,
|
||||
'multi_login' => $multiLogin,
|
||||
];
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
@@ -72,10 +80,11 @@ class SettingsController extends Controller
|
||||
$settings = $request->all();
|
||||
// 将数据入库
|
||||
foreach ($settings as $key => $value) {
|
||||
if ($key == 'access_token' || $key == 'username' || $key == 'password' || $key == 'api_token' || $key == 'api') {
|
||||
if ($key == 'access_token' || $key == 'username' || $key == 'password' || $key == 'api_token' || $key == 'api' || $key == 'port') {
|
||||
continue;
|
||||
}
|
||||
Setting::query()->where('name', $key)->update(['value' => $value]);
|
||||
// 创建或更新
|
||||
Setting::query()->updateOrCreate(['name' => $key], ['value' => $value]);
|
||||
}
|
||||
// 单独处理用户名和密码
|
||||
if ($request->input('username') != $request->user()->username) {
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
* 耗子Linux面板 - 用户控制器
|
||||
* @author 耗子
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@@ -34,15 +36,21 @@ class UsersController extends Controller
|
||||
'errors' => $e->errors()
|
||||
], 422);
|
||||
}
|
||||
if (auth()->attempt(['username' => $credentials['username'], 'password' => $credentials['password']], $credentials['remember'])) {
|
||||
if (auth()->attempt(['username' => $credentials['username'], 'password' => $credentials['password']],
|
||||
$credentials['remember'])) {
|
||||
$user = auth()->user();
|
||||
$user->tokens()->delete();
|
||||
// 多设备登录
|
||||
$multiLogin = Setting::query()->where('name', 'multi_login')->value('value');
|
||||
if ($multiLogin != 1) {
|
||||
$user->tokens()->delete();
|
||||
}
|
||||
$token = $user->createToken('token')->plainTextToken;
|
||||
return response()->json(['code' => 0, 'msg' => '登录成功', 'data' => ['access_token' => $token]]);
|
||||
} else {
|
||||
return response()->json(['code' => 1, 'msg' => '登录失败,用户名或密码错误']);
|
||||
}
|
||||
}
|
||||
|
||||
public function getInfo(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
@@ -30,6 +30,12 @@ class WebsitesController extends Controller
|
||||
'data' => []
|
||||
]);
|
||||
}
|
||||
foreach ($websiteList as $website) {
|
||||
// 如果PHP是0,将其设置为字符串的00
|
||||
if ($website->php == '0') {
|
||||
$website->php = '00';
|
||||
}
|
||||
}
|
||||
return response()->json([
|
||||
'code' => 0,
|
||||
'msg' => '获取成功',
|
||||
@@ -335,10 +341,10 @@ EOF;
|
||||
$website['domain'] .= PHP_EOL.$v;
|
||||
}
|
||||
}
|
||||
// 从nginx配置中root标记位提取全部根目录
|
||||
// 从nginx配置中root标记位提取运行目录
|
||||
$root_raw = $this->cut('# root标记位开始', '# root标记位结束', $nginx_config);
|
||||
preg_match_all('/root\s+(.+);/', $root_raw, $matches2);
|
||||
$website['path'] = $matches2[1][0];
|
||||
$website['root'] = $matches2[1][0];
|
||||
// 从nginx配置中index标记位提取全部默认文件
|
||||
$index_raw = $this->cut('# index标记位开始', '# index标记位结束', $nginx_config);
|
||||
preg_match_all('/index\s+(.+);/', $index_raw, $matches3);
|
||||
@@ -396,6 +402,11 @@ EOF;
|
||||
// 读取访问日志
|
||||
$website['log'] = shell_exec('tail -n 100 /www/wwwlogs/'.$name.'.log');
|
||||
|
||||
// 如果PHP是0,将其设置为字符串的00
|
||||
if ($website['php'] == '0') {
|
||||
$website['php'] = '00';
|
||||
}
|
||||
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
$res['data'] = $website;
|
||||
@@ -413,6 +424,20 @@ EOF;
|
||||
$name = $request->input('name');
|
||||
$config = $request->input('config');
|
||||
|
||||
$website = Website::query()->where('name', $name)->first();
|
||||
if (!$website) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '网站不存在',
|
||||
], 200);
|
||||
}
|
||||
if ($website->status != 1) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '网站已停用,请先启用',
|
||||
], 200);
|
||||
}
|
||||
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
|
||||
@@ -467,12 +492,12 @@ EOF;
|
||||
$configRaw = str_replace($port_config_old, PHP_EOL.$port.PHP_EOL.' ', $configRaw);
|
||||
}
|
||||
|
||||
// 网站目录
|
||||
// 运行目录
|
||||
$pathConfig = $this->cut('# root标记位开始', '# root标记位结束', $configRaw);
|
||||
preg_match_all('/root\s+(.+);/', $pathConfig, $matches1);
|
||||
$pathConfigOld = $matches1[1][0];
|
||||
if (!empty(trim($pathConfigOld)) && $pathConfigOld != PHP_EOL) {
|
||||
$pathConfigNew = str_replace($pathConfigOld, $config['path'], $pathConfig);
|
||||
$pathConfigNew = str_replace($pathConfigOld, $config['root'], $pathConfig);
|
||||
$configRaw = str_replace($pathConfig, $pathConfigNew, $configRaw);
|
||||
}
|
||||
|
||||
@@ -497,7 +522,7 @@ EOF;
|
||||
if (is_dir($config['path'])) {
|
||||
file_put_contents($config['path'].'/.user.ini', $open_basedir);
|
||||
// 为.user.ini文件添加i权限
|
||||
shell_exec('chattr +i '.$config['path'].'/.user.ini');
|
||||
// shell_exec('chattr +i '.$config['path'].'/.user.ini');
|
||||
}
|
||||
} else {
|
||||
// 移除.user.ini文件的i权限
|
||||
@@ -600,8 +625,10 @@ EOL;
|
||||
}
|
||||
|
||||
// 将数据入库
|
||||
Website::query()->where('name', $name)->update(['php' => $config['php']]);
|
||||
Website::query()->where('name', $name)->update(['ssl' => $config['ssl']]);
|
||||
$website->php = $config['php'];
|
||||
$website->ssl = $config['ssl'];
|
||||
$website->path = $config['path'];
|
||||
$website->save();
|
||||
file_put_contents('/www/server/vhost/'.$name.'.conf', $configRaw);
|
||||
file_put_contents('/www/server/vhost/rewrite/'.$name.'.conf', $config['rewrite']);
|
||||
shell_exec('systemctl reload nginx');
|
||||
@@ -637,7 +664,376 @@ EOL;
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
// 裁剪字符串
|
||||
/**
|
||||
* 获取备份列表
|
||||
*/
|
||||
public function getBackupList(): JsonResponse
|
||||
{
|
||||
$backupPath = '/www/backup/website';
|
||||
// 判断备份目录是否存在
|
||||
if (!is_dir($backupPath)) {
|
||||
mkdir($backupPath, 0644, true);
|
||||
}
|
||||
$backupFiles = scandir($backupPath);
|
||||
$backupFiles = array_diff($backupFiles, ['.', '..']);
|
||||
$backupFiles = array_values($backupFiles);
|
||||
$backupFiles = array_map(function ($backupFile) {
|
||||
return [
|
||||
'backup' => $backupFile,
|
||||
'size' => formatBytes(filesize('/www/backup/website/'.$backupFile)),
|
||||
];
|
||||
}, $backupFiles);
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
$res['data'] = $backupFiles;
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建备份
|
||||
*/
|
||||
public function createBackup(Request $request): JsonResponse
|
||||
{
|
||||
// 消毒数据
|
||||
try {
|
||||
$credentials = $this->validate($request, [
|
||||
'name' => 'required|max:255',
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '参数错误:'.$e->getMessage(),
|
||||
'errors' => $e->errors()
|
||||
], 200);
|
||||
}
|
||||
|
||||
$backupPath = '/www/backup/website';
|
||||
// 判断备份目录是否存在
|
||||
if (!is_dir($backupPath)) {
|
||||
mkdir($backupPath, 0644, true);
|
||||
}
|
||||
|
||||
// 从数据库中获取网站目录
|
||||
$sitePath = Website::query()->where('name', $credentials['name'])->value('path');
|
||||
$backupFile = $backupPath.'/'.$credentials['name'].'_'.date('YmdHis').'.zip';
|
||||
shell_exec('zip -r '.$backupFile.' '.$sitePath.' 2>&1');
|
||||
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传备份
|
||||
*/
|
||||
public function uploadBackup(Request $request): JsonResponse
|
||||
{
|
||||
// 消毒数据
|
||||
try {
|
||||
$credentials = $this->validate($request, [
|
||||
'file' => 'required|file',
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '参数错误:'.$e->getMessage(),
|
||||
'errors' => $e->errors()
|
||||
], 200);
|
||||
}
|
||||
|
||||
$file = $request->file('file');
|
||||
$backupPath = '/www/backup/website';
|
||||
|
||||
// 判断备份目录是否存在
|
||||
if (!is_dir($backupPath)) {
|
||||
mkdir($backupPath, 0644, true);
|
||||
}
|
||||
$backupFile = $backupPath.'/'.$file->getClientOriginalName();
|
||||
$file->move($backupPath, $file->getClientOriginalName());
|
||||
|
||||
// 返回文件名
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
$res['data'] = $file->getClientOriginalName();
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复备份
|
||||
*/
|
||||
public function restoreBackup(Request $request): JsonResponse
|
||||
{
|
||||
// 消毒数据
|
||||
try {
|
||||
$credentials = $this->validate($request, [
|
||||
'name' => 'required|max:255',
|
||||
'backup' => 'required|max:255',
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '参数错误:'.$e->getMessage(),
|
||||
'errors' => $e->errors()
|
||||
], 200);
|
||||
}
|
||||
|
||||
$backupPath = '/www/backup/website';
|
||||
// 判断备份目录是否存在
|
||||
if (!is_dir($backupPath)) {
|
||||
mkdir($backupPath, 0644, true);
|
||||
}
|
||||
$backupFile = $backupPath.'/'.$credentials['backup'];
|
||||
// 判断备份文件是否存在
|
||||
if (!is_file($backupFile)) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '备份文件不存在',
|
||||
], 200);
|
||||
}
|
||||
|
||||
shell_exec('rm -rf /www/wwwroot/'.$credentials['name'].'/*');
|
||||
shell_exec('unzip -o '.$backupFile.' -d /www/wwwroot/'.$credentials['name'].' 2>&1');
|
||||
// 设置权限
|
||||
shell_exec('chown -R www:www /www/wwwroot/'.$credentials['name']);
|
||||
shell_exec('chmod -R 755 /www/wwwroot/'.$credentials['name']);
|
||||
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除备份
|
||||
*/
|
||||
public function deleteBackup(Request $request): JsonResponse
|
||||
{
|
||||
// 消毒数据
|
||||
try {
|
||||
$credentials = $this->validate($request, [
|
||||
'backup' => 'required|max:255',
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '参数错误:'.$e->getMessage(),
|
||||
'errors' => $e->errors()
|
||||
], 200);
|
||||
}
|
||||
|
||||
$backupPath = '/www/backup/website';
|
||||
// 判断备份目录是否存在
|
||||
if (!is_dir($backupPath)) {
|
||||
mkdir($backupPath, 0644, true);
|
||||
}
|
||||
$backupFile = $backupPath.'/'.$credentials['backup'];
|
||||
// 判断备份文件是否存在
|
||||
if (!is_file($backupFile)) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '备份文件不存在',
|
||||
], 200);
|
||||
}
|
||||
|
||||
unlink($backupFile);
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置网站配置文件
|
||||
*/
|
||||
public function resetSiteConfig(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$credentials = $this->validate($request, [
|
||||
'name' => 'required|max:255',
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '参数错误:'.$e->getMessage(),
|
||||
'errors' => $e->errors()
|
||||
], 200);
|
||||
}
|
||||
|
||||
$website = Website::query()->where('name', $credentials['name'])->first();
|
||||
if (!$website) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '网站不存在',
|
||||
], 200);
|
||||
}
|
||||
|
||||
// 如果PHP是0,将其设置为字符串的00
|
||||
if ($website['php'] == '0') {
|
||||
$website['php'] = '00';
|
||||
}
|
||||
|
||||
// 更新网站状态为运行
|
||||
$website->status = 1;
|
||||
// 更新网站ssl状态为关闭
|
||||
$website->ssl = 0;
|
||||
$website->save();
|
||||
|
||||
$nginxConfig = <<<EOF
|
||||
# 配置文件中的标记位请勿随意修改,改错将导致面板无法识别!
|
||||
# 有自定义配置需求的,请将自定义的配置写在各标记位下方。
|
||||
server
|
||||
{
|
||||
# port标记位开始
|
||||
listen 80;
|
||||
# port标记位结束
|
||||
# server_name标记位开始
|
||||
server_name localhost;
|
||||
# server_name标记位结束
|
||||
# index标记位开始
|
||||
index index.php index.html;
|
||||
# index标记位结束
|
||||
# root标记位开始
|
||||
root $website[path];
|
||||
# root标记位结束
|
||||
|
||||
# ssl标记位开始
|
||||
# ssl标记位结束
|
||||
|
||||
# php标记位开始
|
||||
include enable-php-$website[php].conf;
|
||||
# php标记位结束
|
||||
|
||||
# waf标记位开始
|
||||
waf on;
|
||||
waf_rule_path /www/server/nginx/ngx_waf/assets/rules/;
|
||||
waf_mode DYNAMIC;
|
||||
waf_cc_deny rate=1000r/m duration=60m;
|
||||
waf_cache capacity=50;
|
||||
# waf标记位结束
|
||||
|
||||
# 错误页配置,可自行设置
|
||||
#error_page 404 /404.html;
|
||||
#error_page 502 /502.html;
|
||||
|
||||
# 伪静态规则引入,修改后将导致面板设置的伪静态规则失效
|
||||
include /www/server/vhost/rewrite/$website[name].conf;
|
||||
|
||||
# 面板默认禁止访问部分敏感目录,可自行修改
|
||||
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn)
|
||||
{
|
||||
return 404;
|
||||
}
|
||||
# 面板默认不记录静态资源的访问日志并开启1小时浏览器缓存,可自行修改
|
||||
location ~ .*\.(js|css)$
|
||||
{
|
||||
expires 1h;
|
||||
error_log /dev/null;
|
||||
access_log /dev/null;
|
||||
}
|
||||
access_log /www/wwwlogs/$website[name].log;
|
||||
error_log /www/wwwlogs/$website[name].log;
|
||||
}
|
||||
EOF;
|
||||
file_put_contents('/www/server/vhost/'.$website['name'].'.conf', $nginxConfig);
|
||||
// 重置伪静态规则
|
||||
shell_exec('echo "" > /www/server/vhost/rewrite/'.$website['name'].'.conf');
|
||||
// 重载nginx
|
||||
shell_exec('systemctl reload nginx');
|
||||
|
||||
// 返回
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置网站运行状态
|
||||
*/
|
||||
public function setSiteStatus(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$credentials = $this->validate($request, [
|
||||
'name' => 'required|max:255',
|
||||
'status' => 'required|in:0,1',
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '参数错误:'.$e->getMessage(),
|
||||
'errors' => $e->errors()
|
||||
], 200);
|
||||
}
|
||||
|
||||
$website = Website::query()->where('name', $credentials['name'])->first();
|
||||
if (!$website) {
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '网站不存在',
|
||||
], 200);
|
||||
}
|
||||
|
||||
$nginxConfig = file_get_contents('/www/server/vhost/'.$website['name'].'.conf');
|
||||
|
||||
// 运行目录
|
||||
$pathConfig = $this->cut('# root标记位开始', '# root标记位结束', $nginxConfig);
|
||||
preg_match_all('/root\s+(.+);/', $pathConfig, $matches1);
|
||||
$pathConfigOld = $matches1[1][0];
|
||||
if (!empty(trim($pathConfigOld)) && $pathConfigOld != PHP_EOL) {
|
||||
if ($credentials['status'] == 0) {
|
||||
$pathConfigNew = str_replace($pathConfigOld, '/www/server/nginx/html', $pathConfig);
|
||||
// 将旧配置追加到新配置中
|
||||
$pathConfigNew .= '# '.$pathConfigOld.PHP_EOL.' ';
|
||||
} else {
|
||||
// 匹配旧配置
|
||||
preg_match_all('/# (.+)/', $pathConfig, $matches2);
|
||||
// 还原旧配置
|
||||
$pathConfigNew = str_replace($pathConfigOld, $matches2[1][0], $pathConfig);
|
||||
// 删除旧配置
|
||||
$pathConfigNew = str_replace(PHP_EOL.' # '.$matches2[1][0], '', $pathConfigNew);
|
||||
}
|
||||
$nginxConfig = str_replace($pathConfig, $pathConfigNew, $nginxConfig);
|
||||
}
|
||||
|
||||
// 默认文件
|
||||
$indexConfig = $this->cut('# index标记位开始', '# index标记位结束', $nginxConfig);
|
||||
preg_match_all('/index\s+(.+);/', $indexConfig, $matches2);
|
||||
$indexConfigOld = $matches2[1][0];
|
||||
if (!empty(trim($indexConfigOld)) && $indexConfigOld != PHP_EOL) {
|
||||
if ($credentials['status'] == 0) {
|
||||
$indexConfigNew = str_replace($indexConfigOld, 'stop.html', $indexConfig);
|
||||
// 将旧配置追加到新配置中
|
||||
$indexConfigNew .= '# '.$indexConfigOld.PHP_EOL.' ';
|
||||
} else {
|
||||
// 匹配旧配置
|
||||
preg_match_all('/# (.+)/', $indexConfig, $matches2);
|
||||
// 还原旧配置
|
||||
$indexConfigNew = str_replace($indexConfigOld, $matches2[1][0], $indexConfig);
|
||||
// 删除旧配置
|
||||
$indexConfigNew = str_replace(PHP_EOL.' # '.$matches2[1][0], '', $indexConfigNew);
|
||||
}
|
||||
$nginxConfig = str_replace($indexConfig, $indexConfigNew, $nginxConfig);
|
||||
}
|
||||
|
||||
// 写入配置文件
|
||||
file_put_contents('/www/server/vhost/'.$website['name'].'.conf', $nginxConfig);
|
||||
|
||||
$website->status = $credentials['status'];
|
||||
$website->save();
|
||||
|
||||
// 重载nginx
|
||||
shell_exec('systemctl reload nginx');
|
||||
|
||||
// 返回
|
||||
$res['code'] = 0;
|
||||
$res['msg'] = 'success';
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪字符串
|
||||
* @param $begin
|
||||
* @param $end
|
||||
* @param $str
|
||||
* @return string
|
||||
*/
|
||||
private function cut($begin, $end, $str): string
|
||||
{
|
||||
$b = mb_strpos($str, $begin) + mb_strlen($begin);
|
||||
|
||||
@@ -88,14 +88,14 @@
|
||||
, url: '/api/panel/cron/getList'
|
||||
, cols: [[
|
||||
{field: 'id', hide: true, title: 'ID', sort: true}
|
||||
, {field: 'name', width: '15%', title: '任务名'}
|
||||
, {field: 'type', width: '10%', title: '任务类型'}
|
||||
, {field: 'name', width: 150, title: '任务名'}
|
||||
, {field: 'type', width: 150, title: '任务类型'}
|
||||
, {field: 'status', title: '启用', width: 100, templet: '#cron-table-status', unresize: true}
|
||||
, {field: 'time', width: '25%', title: '任务周期(cron表达式)'}
|
||||
, {field: 'time', width: 200, title: '任务周期(cron表达式)'}
|
||||
, {field: 'updated_at', title: '上次运行时间'}
|
||||
, {
|
||||
field: 'edit',
|
||||
width: '15%',
|
||||
width: 160,
|
||||
title: '操作',
|
||||
templet: '#cron-table-edit',
|
||||
fixed: 'right',
|
||||
|
||||
@@ -272,8 +272,5 @@ Date: 2022-11-30
|
||||
});
|
||||
});
|
||||
});
|
||||
/**
|
||||
* TODO: 为主页安排一个应用展示
|
||||
*/
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,42 +2,29 @@
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<!--<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="plugin-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">搜索</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="plugin_search" placeholder="请输入关键词(如php)" autocomplete="off"
|
||||
class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-order" lay-submit lay-filter="plugin-search-submit">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="layui-card-header">
|
||||
按钮点击一次即可,请勿重复点击以免重复操作,任务中心在右上角!
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="panel-plugin" lay-filter="panel-plugin"></table>
|
||||
<!-- 操作按钮模板 -->
|
||||
<script type="text/html" id="panel-plugin-control">
|
||||
@{{# if(d.control.installed == true && d.control.allow_uninstall == true){ }}
|
||||
@{{# if(d.control.update == true){ }}
|
||||
@{{# if(d.control.installed == true && d.control.allow_uninstall == true){ }}
|
||||
@{{# if(d.control.update == true){ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update">更新</a>
|
||||
@{{# } }}
|
||||
@{{# } }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="open">管理</a>
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="uninstall">卸载</a>
|
||||
@{{# } else{ }}
|
||||
@{{# if(d.control.installed == true && d.control.allow_uninstall == false){ }}
|
||||
@{{# if(d.control.update == true){ }}
|
||||
@{{# }else{ }}
|
||||
@{{# if(d.control.installed == true && d.control.allow_uninstall == false){ }}
|
||||
@{{# if(d.control.update == true){ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update">更新</a>
|
||||
@{{# } }}
|
||||
@{{# } }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="open">管理</a>
|
||||
@{{# } else{ }}
|
||||
@{{# }else{ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="install">安装</a>
|
||||
@{{# } }}
|
||||
@{{# } }}
|
||||
@{{# } }}
|
||||
@{{# } }}
|
||||
</script>
|
||||
<!-- 首页显示开关 -->
|
||||
<script type="text/html" id="plugin-show">
|
||||
@@ -63,12 +50,19 @@
|
||||
, url: '/api/panel/plugin/getList'
|
||||
, cols: [[
|
||||
{field: 'slug', hide: true, title: 'Slug', sort: true}
|
||||
, {field: 'name', width: '13%', title: '插件名'}
|
||||
, {field: 'describe', width: '42%', title: '描述'}
|
||||
, {field: 'install_version', width: '12%', title: '已装版本'}
|
||||
, {field: 'version', width: '12%', title: '最新版本'}
|
||||
, {field: 'name', width: 150, title: '插件名'}
|
||||
, {field: 'describe', title: '描述'}
|
||||
, {field: 'install_version', width: 140, title: '已装版本'}
|
||||
, {field: 'version', width: 140, title: '最新版本'}
|
||||
, {field: 'show', title: '首页显示', width: 90, templet: '#plugin-show', unresize: true}
|
||||
, {field: 'control', title: '操作', templet: '#panel-plugin-control', fixed: 'right', align: 'left'}
|
||||
, {
|
||||
field: 'control',
|
||||
width: 160,
|
||||
title: '操作',
|
||||
templet: '#panel-plugin-control',
|
||||
fixed: 'right',
|
||||
align: 'left'
|
||||
}
|
||||
]]
|
||||
, page: false
|
||||
, text: '耗子Linux面板:数据加载出现异常!'
|
||||
|
||||
@@ -207,17 +207,12 @@
|
||||
table.render({
|
||||
elem: '#safe-port'
|
||||
, url: '/api/panel/safe/getFirewallRules'
|
||||
//, toolbar: '#website-list-bar'
|
||||
, title: '网站列表'
|
||||
, title: '防火墙'
|
||||
, cols: [[
|
||||
{field: 'port', title: '端口', width: 200}
|
||||
{field: 'port', title: '端口', width: 100}
|
||||
, {field: 'protocol', title: '协议'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#safe-port-setting', width: 150}
|
||||
]]
|
||||
/**
|
||||
* TODO: 分页
|
||||
*/
|
||||
//, page: true
|
||||
});
|
||||
table.on('tool(safe-port)', function (obj) {
|
||||
let data = obj.data;
|
||||
@@ -253,7 +248,7 @@
|
||||
layer.msg('端口号不合法', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
var index = layer.load(2);
|
||||
var index = layer.load();
|
||||
admin.req({
|
||||
url: '/api/panel/safe/setSshPort'
|
||||
, type: 'post'
|
||||
@@ -281,7 +276,7 @@
|
||||
layer.msg('端口号不合法', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
var index = layer.load(2);
|
||||
var index = layer.load();
|
||||
admin.req({
|
||||
url: '/api/panel/safe/addFirewallRule'
|
||||
, type: 'post'
|
||||
|
||||
@@ -26,6 +26,13 @@ Date: 2022-12-01
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">API Token,用于携带访问面板接口</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">多设备登录</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="multi_login" lay-skin="switch" lay-text="ON|OFF"/>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">开启后将允许多设备同时登录面板,可能具有一定安全隐患</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面板名称</label>
|
||||
<div class="layui-input-inline">
|
||||
@@ -105,11 +112,18 @@ Date: 2022-12-01
|
||||
|
||||
// 面板设置
|
||||
form.on('submit(panel_setting_submit)', function (obj) {
|
||||
// 面板API
|
||||
if (obj.field.api === "on") {
|
||||
obj.field.api = 1;
|
||||
} else {
|
||||
obj.field.api = 0;
|
||||
}
|
||||
// 多设备登录
|
||||
if (obj.field.multi_login === "on") {
|
||||
obj.field.multi_login = 1;
|
||||
} else {
|
||||
obj.field.multi_login = 0;
|
||||
}
|
||||
// 提交修改
|
||||
admin.req({
|
||||
url: "/api/panel/setting/save"
|
||||
@@ -121,8 +135,8 @@ Date: 2022-12-01
|
||||
layer.msg('面板设置保存失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.msg('面板设置保存成功!');
|
||||
admin.render();
|
||||
layer.msg('面板设置保存成功!');
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
|
||||
@@ -26,7 +26,7 @@ Date: 2022-12-01
|
||||
<div class="layui-input-block">
|
||||
<select name="php" lay-filter="add-website-php">
|
||||
@{{# layui.each(d.params.php_version, function(index, item){ }}
|
||||
@{{# if(index == "00"){ }}
|
||||
@{{# if(item == "00"){ }}
|
||||
<option value="@{{ item }}" selected="">@{{ item }}</option>
|
||||
@{{# }else{ }}
|
||||
<option value="@{{ item }}">@{{ item }}</option>
|
||||
|
||||
159
resources/views/website/backup.blade.php
Normal file
159
resources/views/website/backup.blade.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<!--
|
||||
Name: 网站 - 备份
|
||||
Author: 耗子
|
||||
Date: 2022-12-02
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs12 layui-col-sm12 layui-col-md12">
|
||||
<table class="layui-hide" id="website-backup-list" lay-filter="website-backup-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份顶部工具栏 -->
|
||||
<script type="text/html" id="website-backup-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backup_website">备份网站</button>
|
||||
<button class="layui-btn layui-btn-sm" id="upload_website_backup">上传备份</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份右侧管理 -->
|
||||
<script type="text/html" id="website-backup-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
console.log(params);
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, upload = layui.upload;
|
||||
console.log(params);
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#website-backup-list'
|
||||
, url: '/api/panel/website/getBackupList'
|
||||
, toolbar: '#website-backup-bar'
|
||||
, title: '备份列表'
|
||||
, cols: [[
|
||||
{field: 'backup', title: '备份名称', width: 500}
|
||||
, {field: 'size', title: '文件大小'}
|
||||
, {field: 'right', title: '操作', width: 150, toolbar: '#website-backup-control'}
|
||||
]]
|
||||
, text: {
|
||||
none: '无备份数据'
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
upload.render({
|
||||
elem: '#upload_website_backup'
|
||||
, url: '/api/panel/website/uploadBackup'
|
||||
, accept: 'file'
|
||||
, exts: 'zip'
|
||||
, before: function (obj) {
|
||||
index = layer.msg('正在上传备份文件,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
}
|
||||
, done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg('上传成功!', {icon: 1});
|
||||
table.reload('website-backup-list');
|
||||
}
|
||||
, error: function (res) {
|
||||
layer.msg('上传失败:' + res.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(website-backup-list)', function (obj) {
|
||||
if (obj.event === 'backup_website') {
|
||||
index = layer.msg('正在备份网站,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/panel/website/createBackup'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
name: params.data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站失败,接口返回' + result);
|
||||
layer.alert('备份失败!');
|
||||
return false;
|
||||
}
|
||||
table.reload('website-backup-list');
|
||||
layer.msg('备份成功!', {icon: 1});
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(website-backup-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除网站备份 <b style="color: red;">' + data.backup + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除网站备份,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/panel/website/deleteBackup"
|
||||
, method: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站备份删除失败,接口返回' + result);
|
||||
layer.msg('网站备份删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('网站备份' + data.backup + '删除成功!');
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'restore') {
|
||||
layer.confirm('高风险操作,确定要恢复网站备份 <b style="color: red;">' + data.backup + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在恢复网站备份,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
data.name = params.data.name;
|
||||
admin.req({
|
||||
url: "/api/panel/website/restoreBackup"
|
||||
, method: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站备份恢复失败,接口返回' + result);
|
||||
layer.msg('网站备份恢复失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('网站备份' + data.backup + '恢复成功!');
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,9 +1,10 @@
|
||||
<!--
|
||||
Name: 网站 - 全局设置
|
||||
Author: 耗子
|
||||
Date: 2022-11-30
|
||||
Date: 2022-12-02
|
||||
-->
|
||||
<script type="text/html" template lay-url="/api/panel/website/getDefaultSettings" lay-done="layui.data.sendParams(d.params)">
|
||||
<script type="text/html" template lay-url="/api/panel/website/getDefaultSettings"
|
||||
lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">默认页</li>
|
||||
@@ -20,7 +21,7 @@ Date: 2022-11-30
|
||||
<div class="layui-tab-item">
|
||||
<!-- 停止页 -->
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
设置站点停止时的提示页面。
|
||||
设置站点停止时的提示页面,设置后需重新开关网站方可生效。
|
||||
</blockquote>
|
||||
<div id="stop-editor" style="height: 400px;">@{{ d.data.stop }}</div>
|
||||
</div>
|
||||
@@ -33,7 +34,7 @@ Date: 2022-11-30
|
||||
<script>
|
||||
let indexEditor = '';
|
||||
let stopEditor = '';
|
||||
layui.data.sendParams = function(params) {
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
@@ -51,7 +52,7 @@ Date: 2022-11-30
|
||||
});
|
||||
|
||||
$('#save-website-default-settings').click(function () {
|
||||
layer.load(2);
|
||||
layer.load();
|
||||
admin.req({
|
||||
url: '/api/panel/website/saveDefaultSettings'
|
||||
, type: 'post'
|
||||
|
||||
@@ -4,7 +4,7 @@ Author: 耗子
|
||||
Date: 2022-12-01
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-tab">
|
||||
<div class="layui-tab" lay-filter="website-edit-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">域名端口</li>
|
||||
<li>基本设置</li>
|
||||
@@ -26,6 +26,7 @@ Date: 2022-12-01
|
||||
class="layui-textarea">@{{ d.params.config.domain }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">端口</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -46,6 +47,13 @@ Date: 2022-12-01
|
||||
class="layui-input" value="@{{ d.params.config.path }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">运行目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="root" autocomplete="off" placeholder="请输入网站运行目录(Laravel等程序需要)"
|
||||
class="layui-input" value="@{{ d.params.config.root }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">默认文档</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -58,7 +66,7 @@ Date: 2022-12-01
|
||||
<div class="layui-input-block">
|
||||
<select name="php" lay-filter="website-php">
|
||||
@{{# layui.each(d.params.php_version, function(index, item){ }}
|
||||
@{{# if(index == "00"){ }}
|
||||
@{{# if(item == d.params.config.php){ }}
|
||||
<option value="@{{ item }}" selected="">@{{ item }}</option>
|
||||
@{{# }else{ }}
|
||||
<option value="@{{ item }}">@{{ item }}</option>
|
||||
@@ -199,8 +207,18 @@ Date: 2022-12-01
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, code = layui.code
|
||||
, form = layui.form;
|
||||
, form = layui.form
|
||||
, element = layui.element;
|
||||
form.render();
|
||||
element.render();
|
||||
element.on('tab(website-edit-tab)', function (data) {
|
||||
if (data.index === 6) {
|
||||
// 隐藏保存按钮
|
||||
$('.layui-footer').hide();
|
||||
} else {
|
||||
$('.layui-footer').show();
|
||||
}
|
||||
});
|
||||
rewriteEditor = ace.edit("rewrite-editor", {
|
||||
mode: "ace/mode/nginx",
|
||||
selectionStyle: "text"
|
||||
@@ -219,7 +237,7 @@ Date: 2022-12-01
|
||||
$("#clean-site-log").click(function () {
|
||||
layer.confirm('确定要清空日志吗?', function (index) {
|
||||
layer.close(index);
|
||||
layer.load(2);
|
||||
layer.load();
|
||||
admin.req({
|
||||
url: '/api/panel/website/clearSiteLog'
|
||||
, type: 'post'
|
||||
@@ -244,7 +262,7 @@ Date: 2022-12-01
|
||||
});
|
||||
|
||||
$('#save-site-config').click(function () {
|
||||
layer.load(2);
|
||||
layer.load();
|
||||
var port = $('textarea[name="port"]').val();
|
||||
var reg = new RegExp(/\n443.*\n?/);
|
||||
// 如果开启了https,就自动添加443端口
|
||||
@@ -270,6 +288,7 @@ Date: 2022-12-01
|
||||
ssl_certificate: $('textarea[name="ssl_certificate"]').val(),
|
||||
ssl_certificate_key: $('textarea[name="ssl_certificate_key"]').val(),
|
||||
path: $('input[name="path"]').val(),
|
||||
root: $('input[name="root"]').val(),
|
||||
index: $('input[name="index"]').val(),
|
||||
php: $('select[name="php"]').val(),
|
||||
open_basedir: $('input[name="open_basedir"]').prop('checked') ? 1 : 0,
|
||||
@@ -298,9 +317,33 @@ Date: 2022-12-01
|
||||
});
|
||||
});
|
||||
|
||||
// 重载配置
|
||||
$('#site-config-restore').click(function (){
|
||||
layer.msg('待开发功能!', {icon: 2});
|
||||
// 重置配置
|
||||
$('#site-config-restore').click(function () {
|
||||
layer.confirm('高风险操作,网站配置重置后所有配置均需重新设置,确定要重置配置吗?', function (index) {
|
||||
index = layer.msg('重置网站配置', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/panel/website/resetSiteConfig'
|
||||
, type: 'post'
|
||||
, data: {name: params.config.name}
|
||||
, success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.alert('重置成功,你需要重新添加域名/端口绑定,设置各配置参数!', function (index) {
|
||||
admin.render();
|
||||
layer.close(index);
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
@@ -16,11 +16,13 @@ Date: 2022-11-28
|
||||
<script type="text/html" id="website-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="website_add">添加网站</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="website_default_settings">全局设置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="website_default_settings">全局设置
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 右侧网站设置和删除网站 -->
|
||||
<script type="text/html" id="website-setting">
|
||||
<script type="text/html" id="website-control">
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="backup">备份</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">设置</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
@@ -77,13 +79,13 @@ Date: 2022-11-28
|
||||
, toolbar: '#website-list-bar'
|
||||
, title: '网站列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '网站名', width: 200, fixed: 'left', unresize: true, sort: true}
|
||||
{field: 'name', title: '网站名', width: 150, unresize: true, sort: true}
|
||||
, {field: 'run', title: '运行', width: 100, templet: '#website-run', unresize: true}
|
||||
, {field: 'path', title: '目录', width: 250}
|
||||
, {field: 'php', title: 'PHP', width: 60}
|
||||
, {field: 'ssl', title: 'SSL', width: 110, templet: '#website-ssl'}
|
||||
, {field: 'note', title: '备注', edit: 'textarea'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#website-setting', width: 150}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#website-control', width: 160}
|
||||
]]
|
||||
/**
|
||||
* TODO: 分页
|
||||
@@ -96,7 +98,7 @@ Date: 2022-11-28
|
||||
if (obj.event === 'website_add') {
|
||||
admin.popup({
|
||||
title: '添加网站'
|
||||
, area: ['70%', '60%']
|
||||
, area: ['80%', '80%']
|
||||
, id: 'LAY-popup-website-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('website/add', {
|
||||
@@ -110,11 +112,10 @@ Date: 2022-11-28
|
||||
} else if (obj.event === 'website_default_settings') {
|
||||
admin.popup({
|
||||
title: '全局设置'
|
||||
, area: ['70%', '60%']
|
||||
, area: ['80%', '80%']
|
||||
, id: 'LAY-popup-website-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('website/default_settings', {
|
||||
}).done(function () {
|
||||
view(this.id).render('website/default_settings', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-website-default-settings');
|
||||
});
|
||||
}
|
||||
@@ -166,7 +167,7 @@ Date: 2022-11-28
|
||||
// 打开编辑网站页面
|
||||
admin.popup({
|
||||
title: '编辑网站 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, area: ['80%', '80%']
|
||||
, id: 'LAY-popup-website-edit'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('website/edit', {
|
||||
@@ -184,12 +185,26 @@ Date: 2022-11-28
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
} else if (obj.event === 'backup') {
|
||||
// 打开备份页面
|
||||
admin.popup({
|
||||
title: '备份管理 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, id: 'LAY-popup-website-backup'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('website/backup', {
|
||||
data: data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-website-backup');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 网站备注编辑
|
||||
table.on('edit(website-list)', function (obj) {
|
||||
var value = obj.value // 得到修改后的值
|
||||
let value = obj.value // 得到修改后的值
|
||||
, data = obj.data; // 得到行数据
|
||||
admin.req({
|
||||
url: "/api/panel/website/updateSiteNote"
|
||||
@@ -216,10 +231,27 @@ Date: 2022-11-28
|
||||
form.on('switch(website-run-checkbox)', function (obj) {
|
||||
let $ = layui.$;
|
||||
let website_name = $(this).data('website-name');
|
||||
let run = obj.elem.checked ? 1 : 0;
|
||||
let status = obj.elem.checked ? 1 : 0;
|
||||
|
||||
//console.log(website_name); //当前行数据
|
||||
layer.msg('待开发功能!', {icon: 2});
|
||||
admin.req({
|
||||
url: "/api/panel/website/setSiteStatus"
|
||||
, method: 'post'
|
||||
, data: {
|
||||
name: website_name,
|
||||
status: status
|
||||
}
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站运行状态设置失败,接口返回' + result);
|
||||
layer.msg('网站运行状态设置失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('网站 ' + website_name + ' 运行状态设置成功!');
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -75,6 +75,15 @@ Route::prefix('panel')->group(function () {
|
||||
Route::post('saveSiteSettings', [WebsitesController::class, 'saveSiteSettings']);
|
||||
Route::post('clearSiteLog', [WebsitesController::class, 'clearSiteLog']);
|
||||
Route::post('updateSiteNote', [WebsitesController::class, 'updateSiteNote']);
|
||||
Route::post('setSiteStatus', [WebsitesController::class, 'setSiteStatus']);
|
||||
// 获取备份列表
|
||||
Route::get('getBackupList', [WebsitesController::class, 'getBackupList']);
|
||||
Route::post('createBackup', [WebsitesController::class, 'createBackup']);
|
||||
Route::post('uploadBackup', [WebsitesController::class, 'uploadBackup']);
|
||||
Route::post('restoreBackup', [WebsitesController::class, 'restoreBackup']);
|
||||
Route::post('deleteBackup', [WebsitesController::class, 'deleteBackup']);
|
||||
// 重置网站配置
|
||||
Route::post('resetSiteConfig', [WebsitesController::class, 'resetSiteConfig']);
|
||||
});
|
||||
// 监控
|
||||
Route::middleware('auth:sanctum')->prefix('monitor')->group(function () {
|
||||
|
||||
@@ -36,6 +36,8 @@ Route::prefix('panel/views')->group(function () {
|
||||
Route::view('add', 'website.add');
|
||||
// 编辑
|
||||
Route::view('edit', 'website.edit');
|
||||
// 备份
|
||||
Route::view('backup', 'website.backup');
|
||||
});
|
||||
// 监控
|
||||
Route::view('monitor', 'monitor');
|
||||
|
||||
Reference in New Issue
Block a user