registerThemeViewPaths(); } /** * 注册主题视图路径 */ private function registerThemeViewPaths(): void { // 系统主题路径 $systemPath = base_path(self::SYSTEM_THEME_DIR); if (File::exists($systemPath)) { View::addNamespace('theme', $systemPath); } // 用户主题路径 $userPath = base_path(self::USER_THEME_DIR); if (File::exists($userPath)) { View::prependNamespace('theme', $userPath); } } /** * 获取主题视图路径 */ public function getThemeViewPath(string $theme): ?string { $themePath = $this->getThemePath($theme); if (!$themePath) { return null; } return $themePath . '/dashboard.blade.php'; } /** * 获取所有可用主题列表 */ public function getList(): array { $themes = []; // 获取系统主题 $systemPath = base_path(self::SYSTEM_THEME_DIR); if (File::exists($systemPath)) { $themes = $this->getThemesFromPath($systemPath, false); } // 获取用户主题 $userPath = base_path(self::USER_THEME_DIR); if (File::exists($userPath)) { $themes = array_merge($themes, $this->getThemesFromPath($userPath, true)); } return $themes; } /** * 从指定路径获取主题列表 */ private function getThemesFromPath(string $path, bool $canDelete): array { return collect(File::directories($path)) ->mapWithKeys(function ($dir) use ($canDelete) { $name = basename($dir); // 检查必要文件是否存在 if ( !File::exists($dir . '/' . self::CONFIG_FILE) || !File::exists($dir . '/dashboard.blade.php') ) { return []; } $config = $this->readConfigFile($name); if (!$config) { return []; } $config['can_delete'] = $canDelete && $name !== admin_setting('current_theme'); $config['is_system'] = !$canDelete; return [$name => $config]; })->toArray(); } /** * 上传新主题 */ public function upload(UploadedFile $file): bool { $zip = new ZipArchive; $tmpPath = storage_path('tmp/' . uniqid()); try { if ($zip->open($file->path()) !== true) { throw new Exception('无效的主题包'); } // 查找配置文件 $configEntry = collect(range(0, $zip->numFiles - 1)) ->map(fn($i) => $zip->getNameIndex($i)) ->first(fn($name) => basename($name) === self::CONFIG_FILE); if (!$configEntry) { throw new Exception('主题配置文件不存在'); } // 解压并读取配置 $zip->extractTo($tmpPath); $zip->close(); $sourcePath = $tmpPath . '/' . rtrim(dirname($configEntry), '.'); $configFile = $sourcePath . '/' . self::CONFIG_FILE; if (!File::exists($configFile)) { throw new Exception('主题配置文件不存在'); } $config = json_decode(File::get($configFile), true); if (empty($config['name'])) { throw new Exception('主题名称未配置'); } // 检查是否为系统主题 if (in_array($config['name'], self::SYSTEM_THEMES)) { throw new Exception('不能上传与系统主题同名的主题'); } // 检查必要文件 if (!File::exists($sourcePath . '/dashboard.blade.php')) { throw new Exception('缺少必要的主题文件:dashboard.blade.php'); } // 确保目标目录存在 $userThemePath = base_path(self::USER_THEME_DIR); if (!File::exists($userThemePath)) { File::makeDirectory($userThemePath, 0755, true); } $targetPath = $userThemePath . $config['name']; if (File::exists($targetPath)) { throw new Exception('主题已存在'); } File::copyDirectory($sourcePath, $targetPath); $this->initConfig($config['name']); return true; } catch (Exception $e) { throw $e; } finally { // 清理临时文件 if (File::exists($tmpPath)) { File::deleteDirectory($tmpPath); } } } /** * 切换主题 */ public function switch(string $theme): bool { $currentTheme = admin_setting('current_theme'); if ($theme === $currentTheme) { return true; } try { // 验证主题是否存在 $themePath = $this->getThemePath($theme); if (!$themePath) { throw new Exception('主题不存在'); } // 验证视图文件是否存在 if (!File::exists($this->getThemeViewPath($theme))) { throw new Exception('主题视图文件不存在'); } // 复制主题文件到public目录 $targetPath = public_path('theme/' . $theme); if (!File::copyDirectory($themePath, $targetPath)) { throw new Exception('复制主题文件失败'); } // 清理旧主题文件 if ($currentTheme) { $oldPath = public_path('theme/' . $currentTheme); if (File::exists($oldPath)) { File::deleteDirectory($oldPath); } } admin_setting(['current_theme' => $theme]); return true; } catch (Exception $e) { Log::error('Theme switch failed', ['theme' => $theme, 'error' => $e->getMessage()]); throw $e; } } /** * 删除主题 */ public function delete(string $theme): bool { try { // 检查是否为系统主题 if (in_array($theme, self::SYSTEM_THEMES)) { throw new Exception('系统主题不能删除'); } // 检查是否为当前使用的主题 if ($theme === admin_setting('current_theme')) { throw new Exception('当前使用的主题不能删除'); } // 获取主题路径 $themePath = base_path(self::USER_THEME_DIR . $theme); if (!File::exists($themePath)) { throw new Exception('主题不存在'); } // 删除主题文件 File::deleteDirectory($themePath); // 删除public目录下的主题文件 $publicPath = public_path('theme/' . $theme); if (File::exists($publicPath)) { File::deleteDirectory($publicPath); } // 清理主题配置 admin_setting([self::SETTING_PREFIX . $theme => null]); return true; } catch (Exception $e) { Log::error('Theme deletion failed', ['theme' => $theme, 'error' => $e->getMessage()]); throw $e; } } /** * 检查主题是否存在 */ public function exists(string $theme): bool { return $this->getThemePath($theme) !== null; } /** * 获取主题路径 */ public function getThemePath(string $theme): ?string { $systemPath = base_path(self::SYSTEM_THEME_DIR . $theme); if (File::exists($systemPath)) { return $systemPath; } $userPath = base_path(self::USER_THEME_DIR . $theme); if (File::exists($userPath)) { return $userPath; } return null; } /** * 获取主题配置 */ public function getConfig(string $theme): ?array { $config = admin_setting(self::SETTING_PREFIX . $theme); if ($config === null) { $this->initConfig($theme); $config = admin_setting(self::SETTING_PREFIX . $theme); } return $config; } /** * 更新主题配置 */ public function updateConfig(string $theme, array $config): bool { try { // 验证主题是否存在 if (!$this->getThemePath($theme)) { throw new Exception('主题不存在'); } $schema = $this->readConfigFile($theme); if (!$schema) { throw new Exception('主题配置文件无效'); } // 只保留有效的配置字段 $validFields = collect($schema['configs'] ?? [])->pluck('field_name')->toArray(); $validConfig = collect($config) ->only($validFields) ->toArray(); $currentConfig = $this->getConfig($theme) ?? []; $newConfig = array_merge($currentConfig, $validConfig); admin_setting([self::SETTING_PREFIX . $theme => $newConfig]); return true; } catch (Exception $e) { Log::error('Config update failed', ['theme' => $theme, 'error' => $e->getMessage()]); throw $e; } } /** * 读取主题配置文件 */ private function readConfigFile(string $theme): ?array { $themePath = $this->getThemePath($theme); if (!$themePath) { return null; } $file = $themePath . '/' . self::CONFIG_FILE; return File::exists($file) ? json_decode(File::get($file), true) : null; } /** * 初始化主题配置 */ private function initConfig(string $theme): void { $config = $this->readConfigFile($theme); if (!$config) { return; } $defaults = collect($config['configs'] ?? []) ->mapWithKeys(fn($col) => [$col['field_name'] => $col['default_value'] ?? '']) ->toArray(); admin_setting([self::SETTING_PREFIX . $theme => $defaults]); } }