mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-24 20:17:32 +08:00
fix: resolve theme refresh issue after updates
This commit is contained in:
@@ -49,7 +49,7 @@ class XboardUpdate extends Command
|
|||||||
$updateService = new UpdateService();
|
$updateService = new UpdateService();
|
||||||
$updateService->updateVersionCache();
|
$updateService->updateVersionCache();
|
||||||
$themeService = app(ThemeService::class);
|
$themeService = app(ThemeService::class);
|
||||||
$themeService->switch(admin_setting('current_theme'));
|
$themeService->refreshCurrentTheme();
|
||||||
$this->info('更新完毕,队列服务已重启,你无需进行任何操作。');
|
$this->info('更新完毕,队列服务已重启,你无需进行任何操作。');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,17 +23,15 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册主题视图路径
|
* Register theme view paths
|
||||||
*/
|
*/
|
||||||
private function registerThemeViewPaths(): void
|
private function registerThemeViewPaths(): void
|
||||||
{
|
{
|
||||||
// 系统主题路径
|
|
||||||
$systemPath = base_path(self::SYSTEM_THEME_DIR);
|
$systemPath = base_path(self::SYSTEM_THEME_DIR);
|
||||||
if (File::exists($systemPath)) {
|
if (File::exists($systemPath)) {
|
||||||
View::addNamespace('theme', $systemPath);
|
View::addNamespace('theme', $systemPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户主题路径
|
|
||||||
$userPath = base_path(self::USER_THEME_DIR);
|
$userPath = base_path(self::USER_THEME_DIR);
|
||||||
if (File::exists($userPath)) {
|
if (File::exists($userPath)) {
|
||||||
View::prependNamespace('theme', $userPath);
|
View::prependNamespace('theme', $userPath);
|
||||||
@@ -41,7 +39,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取主题视图路径
|
* Get theme view path
|
||||||
*/
|
*/
|
||||||
public function getThemeViewPath(string $theme): ?string
|
public function getThemeViewPath(string $theme): ?string
|
||||||
{
|
{
|
||||||
@@ -53,7 +51,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有可用主题列表
|
* Get all available themes
|
||||||
*/
|
*/
|
||||||
public function getList(): array
|
public function getList(): array
|
||||||
{
|
{
|
||||||
@@ -75,14 +73,13 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从指定路径获取主题列表
|
* Get themes from specified path
|
||||||
*/
|
*/
|
||||||
private function getThemesFromPath(string $path, bool $canDelete): array
|
private function getThemesFromPath(string $path, bool $canDelete): array
|
||||||
{
|
{
|
||||||
return collect(File::directories($path))
|
return collect(File::directories($path))
|
||||||
->mapWithKeys(function ($dir) use ($canDelete) {
|
->mapWithKeys(function ($dir) use ($canDelete) {
|
||||||
$name = basename($dir);
|
$name = basename($dir);
|
||||||
// 检查必要文件是否存在
|
|
||||||
if (
|
if (
|
||||||
!File::exists($dir . '/' . self::CONFIG_FILE) ||
|
!File::exists($dir . '/' . self::CONFIG_FILE) ||
|
||||||
!File::exists($dir . '/dashboard.blade.php')
|
!File::exists($dir . '/dashboard.blade.php')
|
||||||
@@ -101,7 +98,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传新主题
|
* Upload new theme
|
||||||
*/
|
*/
|
||||||
public function upload(UploadedFile $file): bool
|
public function upload(UploadedFile $file): bool
|
||||||
{
|
{
|
||||||
@@ -110,19 +107,17 @@ class ThemeService
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if ($zip->open($file->path()) !== true) {
|
if ($zip->open($file->path()) !== true) {
|
||||||
throw new Exception('无效的主题包');
|
throw new Exception('Invalid theme package');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找配置文件
|
|
||||||
$configEntry = collect(range(0, $zip->numFiles - 1))
|
$configEntry = collect(range(0, $zip->numFiles - 1))
|
||||||
->map(fn($i) => $zip->getNameIndex($i))
|
->map(fn($i) => $zip->getNameIndex($i))
|
||||||
->first(fn($name) => basename($name) === self::CONFIG_FILE);
|
->first(fn($name) => basename($name) === self::CONFIG_FILE);
|
||||||
|
|
||||||
if (!$configEntry) {
|
if (!$configEntry) {
|
||||||
throw new Exception('主题配置文件不存在');
|
throw new Exception('Theme config file not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解压并读取配置
|
|
||||||
$zip->extractTo($tmpPath);
|
$zip->extractTo($tmpPath);
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
@@ -130,25 +125,22 @@ class ThemeService
|
|||||||
$configFile = $sourcePath . '/' . self::CONFIG_FILE;
|
$configFile = $sourcePath . '/' . self::CONFIG_FILE;
|
||||||
|
|
||||||
if (!File::exists($configFile)) {
|
if (!File::exists($configFile)) {
|
||||||
throw new Exception('主题配置文件不存在');
|
throw new Exception('Theme config file not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = json_decode(File::get($configFile), true);
|
$config = json_decode(File::get($configFile), true);
|
||||||
if (empty($config['name'])) {
|
if (empty($config['name'])) {
|
||||||
throw new Exception('主题名称未配置');
|
throw new Exception('Theme name not configured');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否为系统主题
|
|
||||||
if (in_array($config['name'], self::SYSTEM_THEMES)) {
|
if (in_array($config['name'], self::SYSTEM_THEMES)) {
|
||||||
throw new Exception('不能上传与系统主题同名的主题');
|
throw new Exception('Cannot upload theme with same name as system theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查必要文件
|
|
||||||
if (!File::exists($sourcePath . '/dashboard.blade.php')) {
|
if (!File::exists($sourcePath . '/dashboard.blade.php')) {
|
||||||
throw new Exception('缺少必要的主题文件:dashboard.blade.php');
|
throw new Exception('Missing required theme file: dashboard.blade.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保目标目录存在
|
|
||||||
$userThemePath = base_path(self::USER_THEME_DIR);
|
$userThemePath = base_path(self::USER_THEME_DIR);
|
||||||
if (!File::exists($userThemePath)) {
|
if (!File::exists($userThemePath)) {
|
||||||
File::makeDirectory($userThemePath, 0755, true);
|
File::makeDirectory($userThemePath, 0755, true);
|
||||||
@@ -158,18 +150,19 @@ class ThemeService
|
|||||||
if (File::exists($targetPath)) {
|
if (File::exists($targetPath)) {
|
||||||
$oldConfigFile = $targetPath . '/config.json';
|
$oldConfigFile = $targetPath . '/config.json';
|
||||||
if (!File::exists($oldConfigFile)) {
|
if (!File::exists($oldConfigFile)) {
|
||||||
throw new Exception('已存在主题缺少配置文件');
|
throw new Exception('Existing theme missing config file');
|
||||||
}
|
}
|
||||||
$oldConfig = json_decode(File::get($oldConfigFile), true);
|
$oldConfig = json_decode(File::get($oldConfigFile), true);
|
||||||
$oldVersion = $oldConfig['version'] ?? '0.0.0';
|
$oldVersion = $oldConfig['version'] ?? '0.0.0';
|
||||||
$newVersion = $config['version'] ?? '0.0.0';
|
$newVersion = $config['version'] ?? '0.0.0';
|
||||||
if (version_compare($newVersion, $oldVersion, '>')) {
|
if (version_compare($newVersion, $oldVersion, '>')) {
|
||||||
|
$this->cleanupThemeFiles($config['name']);
|
||||||
File::deleteDirectory($targetPath);
|
File::deleteDirectory($targetPath);
|
||||||
File::copyDirectory($sourcePath, $targetPath);
|
File::copyDirectory($sourcePath, $targetPath);
|
||||||
$this->initConfig($config['name']);
|
$this->initConfig($config['name']);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw new Exception('主题已存在且不是新版本');
|
throw new Exception('Theme exists and not a newer version');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +174,6 @@ class ThemeService
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
} finally {
|
} finally {
|
||||||
// 清理临时文件
|
|
||||||
if (File::exists($tmpPath)) {
|
if (File::exists($tmpPath)) {
|
||||||
File::deleteDirectory($tmpPath);
|
File::deleteDirectory($tmpPath);
|
||||||
}
|
}
|
||||||
@@ -189,7 +181,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换主题
|
* Switch theme
|
||||||
*/
|
*/
|
||||||
public function switch(string|null $theme): bool
|
public function switch(string|null $theme): bool
|
||||||
{
|
{
|
||||||
@@ -200,29 +192,22 @@ class ThemeService
|
|||||||
$currentTheme = admin_setting('current_theme');
|
$currentTheme = admin_setting('current_theme');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 验证主题是否存在
|
|
||||||
$themePath = $this->getThemePath($theme);
|
$themePath = $this->getThemePath($theme);
|
||||||
if (!$themePath) {
|
if (!$themePath) {
|
||||||
throw new Exception('主题不存在');
|
throw new Exception('Theme not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证视图文件是否存在
|
|
||||||
if (!File::exists($this->getThemeViewPath($theme))) {
|
if (!File::exists($this->getThemeViewPath($theme))) {
|
||||||
throw new Exception('主题视图文件不存在');
|
throw new Exception('Theme view file not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清理旧主题文件
|
if ($currentTheme && $currentTheme !== $theme) {
|
||||||
if ($currentTheme) {
|
$this->cleanupThemeFiles($currentTheme);
|
||||||
$oldPath = public_path('theme/' . $currentTheme);
|
|
||||||
if (File::exists($oldPath)) {
|
|
||||||
File::deleteDirectory($oldPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制主题文件到public目录
|
|
||||||
$targetPath = public_path('theme/' . $theme);
|
$targetPath = public_path('theme/' . $theme);
|
||||||
if (!File::copyDirectory($themePath, $targetPath)) {
|
if (!File::copyDirectory($themePath, $targetPath)) {
|
||||||
throw new Exception('复制主题文件失败');
|
throw new Exception('Failed to copy theme files');
|
||||||
}
|
}
|
||||||
|
|
||||||
admin_setting(['current_theme' => $theme]);
|
admin_setting(['current_theme' => $theme]);
|
||||||
@@ -235,37 +220,26 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除主题
|
* Delete theme
|
||||||
*/
|
*/
|
||||||
public function delete(string $theme): bool
|
public function delete(string $theme): bool
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// 检查是否为系统主题
|
|
||||||
if (in_array($theme, self::SYSTEM_THEMES)) {
|
if (in_array($theme, self::SYSTEM_THEMES)) {
|
||||||
throw new Exception('系统主题不能删除');
|
throw new Exception('System theme cannot be deleted');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否为当前使用的主题
|
|
||||||
if ($theme === admin_setting('current_theme')) {
|
if ($theme === admin_setting('current_theme')) {
|
||||||
throw new Exception('当前使用的主题不能删除');
|
throw new Exception('Current theme cannot be deleted');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取主题路径
|
|
||||||
$themePath = base_path(self::USER_THEME_DIR . $theme);
|
$themePath = base_path(self::USER_THEME_DIR . $theme);
|
||||||
if (!File::exists($themePath)) {
|
if (!File::exists($themePath)) {
|
||||||
throw new Exception('主题不存在');
|
throw new Exception('Theme not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除主题文件
|
$this->cleanupThemeFiles($theme);
|
||||||
File::deleteDirectory($themePath);
|
File::deleteDirectory($themePath);
|
||||||
|
|
||||||
// 删除public目录下的主题文件
|
|
||||||
$publicPath = public_path('theme/' . $theme);
|
|
||||||
if (File::exists($publicPath)) {
|
|
||||||
File::deleteDirectory($publicPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理主题配置
|
|
||||||
admin_setting([self::SETTING_PREFIX . $theme => null]);
|
admin_setting([self::SETTING_PREFIX . $theme => null]);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -276,7 +250,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查主题是否存在
|
* Check if theme exists
|
||||||
*/
|
*/
|
||||||
public function exists(string $theme): bool
|
public function exists(string $theme): bool
|
||||||
{
|
{
|
||||||
@@ -284,7 +258,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取主题路径
|
* Get theme path
|
||||||
*/
|
*/
|
||||||
public function getThemePath(string $theme): ?string
|
public function getThemePath(string $theme): ?string
|
||||||
{
|
{
|
||||||
@@ -302,7 +276,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取主题配置
|
* Get theme config
|
||||||
*/
|
*/
|
||||||
public function getConfig(string $theme): ?array
|
public function getConfig(string $theme): ?array
|
||||||
{
|
{
|
||||||
@@ -315,22 +289,20 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新主题配置
|
* Update theme config
|
||||||
*/
|
*/
|
||||||
public function updateConfig(string $theme, array $config): bool
|
public function updateConfig(string $theme, array $config): bool
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// 验证主题是否存在
|
|
||||||
if (!$this->getThemePath($theme)) {
|
if (!$this->getThemePath($theme)) {
|
||||||
throw new Exception('主题不存在');
|
throw new Exception('Theme not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$schema = $this->readConfigFile($theme);
|
$schema = $this->readConfigFile($theme);
|
||||||
if (!$schema) {
|
if (!$schema) {
|
||||||
throw new Exception('主题配置文件无效');
|
throw new Exception('Invalid theme config file');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只保留有效的配置字段
|
|
||||||
$validFields = collect($schema['configs'] ?? [])->pluck('field_name')->toArray();
|
$validFields = collect($schema['configs'] ?? [])->pluck('field_name')->toArray();
|
||||||
$validConfig = collect($config)
|
$validConfig = collect($config)
|
||||||
->only($validFields)
|
->only($validFields)
|
||||||
@@ -349,7 +321,7 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取主题配置文件
|
* Read theme config file
|
||||||
*/
|
*/
|
||||||
private function readConfigFile(string $theme): ?array
|
private function readConfigFile(string $theme): ?array
|
||||||
{
|
{
|
||||||
@@ -363,7 +335,68 @@ class ThemeService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化主题配置
|
* Clean up theme files including public directory
|
||||||
|
*/
|
||||||
|
public function cleanupThemeFiles(string $theme): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$publicThemePath = public_path('theme/' . $theme);
|
||||||
|
if (File::exists($publicThemePath)) {
|
||||||
|
File::deleteDirectory($publicThemePath);
|
||||||
|
Log::info('Cleaned up public theme files', ['theme' => $theme, 'path' => $publicThemePath]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cacheKey = "theme_{$theme}_assets";
|
||||||
|
if (cache()->has($cacheKey)) {
|
||||||
|
cache()->forget($cacheKey);
|
||||||
|
Log::info('Cleaned up theme cache', ['theme' => $theme, 'cache_key' => $cacheKey]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::warning('Failed to cleanup theme files', [
|
||||||
|
'theme' => $theme,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force refresh current theme public files
|
||||||
|
*/
|
||||||
|
public function refreshCurrentTheme(): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$currentTheme = admin_setting('current_theme');
|
||||||
|
if (!$currentTheme) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cleanupThemeFiles($currentTheme);
|
||||||
|
|
||||||
|
$themePath = $this->getThemePath($currentTheme);
|
||||||
|
if (!$themePath) {
|
||||||
|
throw new Exception('Current theme path not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetPath = public_path('theme/' . $currentTheme);
|
||||||
|
if (!File::copyDirectory($themePath, $targetPath)) {
|
||||||
|
throw new Exception('Failed to copy theme files');
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('Refreshed current theme files', ['theme' => $currentTheme]);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error('Failed to refresh current theme', [
|
||||||
|
'theme' => $currentTheme ?? 'unknown',
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize theme config
|
||||||
*/
|
*/
|
||||||
private function initConfig(string $theme): void
|
private function initConfig(string $theme): void
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user