feat: support theme update and various improvements

- Add support for updating themes if a newer version is uploaded
- Hide config button for plugins without configuration items
- Auto refresh theme cache after panel update
- Fix issue where user used traffic cannot be set as a decimal
- Fix subscription issue for shadowrocket in v2board theme
This commit is contained in:
xboard
2025-07-15 01:26:14 +08:00
parent f6cf6706c7
commit 706ba5a7a9
7 changed files with 42 additions and 30 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Console\Commands;
use App\Services\ThemeService;
use App\Services\UpdateService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
@@ -46,6 +47,8 @@ class XboardUpdate extends Command
Artisan::call('horizon:terminate');
$updateService = new UpdateService();
$updateService->updateVersionCache();
$themeService = app(ThemeService::class);
$themeService->switch(admin_setting('current_theme'));
$this->info('更新完毕,队列服务已重启,你无需进行任何操作。');
}
}

View File

@@ -206,9 +206,10 @@ class UserController extends Controller
if (!$user) {
return $this->fail([400202, '用户不存在']);
}
// 检查邮箱是否被使用
if (User::where('email', $params['email'])->first() && $user->email !== $params['email']) {
return $this->fail([400201, '邮箱已被使用']);
if (isset($params['email'])) {
if (User::where('email', $params['email'])->first() && $user->email !== $params['email']) {
return $this->fail([400201, '邮箱已被使用']);
}
}
// 处理密码
if (isset($params['password'])) {
@@ -223,7 +224,6 @@ class UserController extends Controller
if (!$plan) {
return $this->fail([400202, '订阅计划不存在']);
}
// return json_encode($plan);
$params['group_id'] = $plan->group_id;
}
// 处理邀请用户

View File

@@ -14,7 +14,8 @@ class UserUpdate extends FormRequest
public function rules()
{
return [
'email' => 'required|email:strict',
'id' => 'required|integer',
'email' => 'email:strict',
'password' => 'nullable|min:8',
'transfer_enable' => 'numeric',
'expired_at' => 'nullable|integer',

View File

@@ -156,7 +156,21 @@ class ThemeService
$targetPath = $userThemePath . $config['name'];
if (File::exists($targetPath)) {
throw new Exception('主题已存在');
$oldConfigFile = $targetPath . '/config.json';
if (!File::exists($oldConfigFile)) {
throw new Exception('已存在主题缺少配置文件');
}
$oldConfig = json_decode(File::get($oldConfigFile), true);
$oldVersion = $oldConfig['version'] ?? '0.0.0';
$newVersion = $config['version'] ?? '0.0.0';
if (version_compare($newVersion, $oldVersion, '>')) {
File::deleteDirectory($targetPath);
File::copyDirectory($sourcePath, $targetPath);
$this->initConfig($config['name']);
return true;
} else {
throw new Exception('主题已存在且不是新版本');
}
}
File::copyDirectory($sourcePath, $targetPath);
@@ -180,9 +194,6 @@ class ThemeService
public function switch(string $theme): bool
{
$currentTheme = admin_setting('current_theme');
if ($theme === $currentTheme) {
return true;
}
try {
// 验证主题是否存在
@@ -196,12 +207,6 @@ class ThemeService
throw new Exception('主题视图文件不存在');
}
// 复制主题文件到public目录
$targetPath = public_path('theme/' . $theme);
if (!File::copyDirectory($themePath, $targetPath)) {
throw new Exception('复制主题文件失败');
}
// 清理旧主题文件
if ($currentTheme) {
$oldPath = public_path('theme/' . $currentTheme);
@@ -210,6 +215,12 @@ class ThemeService
}
}
// 复制主题文件到public目录
$targetPath = public_path('theme/' . $theme);
if (!File::copyDirectory($themePath, $targetPath)) {
throw new Exception('复制主题文件失败');
}
admin_setting(['current_theme' => $theme]);
return true;

File diff suppressed because one or more lines are too long

View File

@@ -30,7 +30,6 @@ Route::get('/', function (Request $request) {
$themeService = new ThemeService();
try {
// 检查主题是否存在,不存在则尝试切换到默认主题
if (!$themeService->exists($theme)) {
if ($theme !== 'Xboard') {
Log::warning('Theme not found, switching to default theme', ['theme' => $theme]);
@@ -40,12 +39,10 @@ Route::get('/', function (Request $request) {
$themeService->switch($theme);
}
// 检查主题视图文件是否存在
if (!$themeService->getThemeViewPath($theme)) {
throw new Exception('主题视图文件不存在');
}
// 检查主题是否已复制到public目录
$publicThemePath = public_path('theme/' . $theme);
if (!File::exists($publicThemePath)) {
$themePath = $themeService->getThemePath($theme);

File diff suppressed because one or more lines are too long