themesPath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'themes'; } /** * 获取所有可用模板列表 * @return array */ public function getThemeList(): array { $themes = []; $dirs = $this->scanThemeDirs(); foreach ($dirs as $dir) { $config = $this->readThemeConfig($dir); $preview = $this->getThemePreview($dir); $themes[] = [ 'key' => $dir, 'name' => $config['name'] ?? $dir, 'description' => $config['description'] ?? '', 'version' => $config['version'] ?? '1.0.0', 'author' => $config['author'] ?? '', 'preview' => $preview, 'path' => '/themes/' . $dir . '/index.html', 'fields' => $config['fields'] ?? [], ]; } return $themes; } /** * 扫描模板目录 * @return array */ private function scanThemeDirs(): array { $dirs = []; if (!is_dir($this->themesPath)) { return $dirs; } $items = scandir($this->themesPath); foreach ($items as $item) { if ($item === '.' || $item === '..') { continue; } $fullPath = $this->themesPath . DIRECTORY_SEPARATOR . $item; // 检查是否有 index.html 或 index.php if (is_dir($fullPath) && (is_file($fullPath . DIRECTORY_SEPARATOR . 'index.html') || is_file($fullPath . DIRECTORY_SEPARATOR . 'index.php'))) { $dirs[] = $item; } } return $dirs; } /** * 读取模板配置文件 * @param string $themeDir * @return array */ private function readThemeConfig(string $themeDir): array { $configPath = $this->themesPath . DIRECTORY_SEPARATOR . $themeDir . DIRECTORY_SEPARATOR . 'config.json'; if (!is_file($configPath)) { return []; } $content = file_get_contents($configPath); $config = json_decode($content, true); return $config ?? []; } /** * 获取模板预览图 * @param string $themeDir * @return string */ private function getThemePreview(string $themeDir): string { $previewPath = '/themes/' . $themeDir . '/preview.png'; // 如果 preview.png 不存在,使用默认占位图 $fullPath = $this->themesPath . DIRECTORY_SEPARATOR . $themeDir . DIRECTORY_SEPARATOR . 'preview.png'; if (!is_file($fullPath)) { return 'https://picsum.photos/300/200?random=' . ord($themeDir[0]); } return $previewPath; } /** * 获取当前激活的模板Key * @param int $tid 租户ID * @return string */ public function getCurrentTheme(int $tid) { // 直接通过 tid 查询对应的 value $value = TemplateSiteConfig::where('tid', $tid)->value('value'); return $value; } /** * 切换当前模板 * @param int $tid 租户ID * @param string $themeKey * @return bool */ public function switchTheme(int $tid, string $themeKey): bool { // 验证模板是否存在 $themes = $this->getThemeList(); $exists = false; foreach ($themes as $theme) { if ($theme['key'] === $themeKey) { $exists = true; break; } } if (!$exists) { return false; } try { // 查找或创建配置记录 $where = [['key', '=', 'current_theme'], ['delete_time', '=', null]]; if ($tid > 0) { $where[] = ['tid', '=', $tid]; } $config = TemplateSiteConfig::where($where) ->find(); $now = date('Y-m-d H:i:s'); if ($config) { TemplateSiteConfig::where('id', $config['id'])->update([ 'value' => $themeKey, 'update_time' => $now ]); } else { TemplateSiteConfig::insert([ 'tid' => $tid, 'key' => 'current_theme', 'value' => $themeKey, 'create_time' => $now, 'update_time' => $now ]); } return true; } catch (\Exception $e) { return false; } } /** * 获取模板数据(用于前端渲染) * @param int $tid 租户ID * @param string|null $themeKey * @return array */ public function getThemeData(int $tid = 0, ?string $themeKey = null): array { $themeKey = $themeKey ?? $this->getCurrentTheme($tid); try { if ($tid > 0) { $where[] = ['tid', '=', $tid]; } $configData = TemplateSiteConfig::where($where) ->select() ->toArray(); $data = []; foreach ($configData as $item) { // 去掉 field_ 前缀 $fieldKey = substr($item['key'], 6); $data[$fieldKey] = $item['value']; } return [ 'theme_key' => $themeKey, 'theme_path' => '/themes/' . $themeKey . '/index.html', 'data' => $data ]; } catch (\Exception $e) { return [ 'theme_key' => $themeKey, 'theme_path' => '/themes/' . $themeKey . '/index.html', 'data' => [] ]; } } /** * 保存模板字段数据 * @param int $tid 租户ID * @param string $themeKey * @param string $fieldKey * @param mixed $fieldValue * @return bool */ public function saveThemeField(int $tid, string $themeKey, string $fieldKey, $fieldValue): bool { try { // 使用 TemplateSiteConfig 表,key 格式为 field_xxx $configKey = 'field_' . $fieldKey; $where = [ ['key', '=', $configKey], ['delete_time', '=', null] ]; if ($tid > 0) { $where[] = ['tid', '=', $tid]; } $existing = TemplateSiteConfig::where($where) ->find(); $value = is_array($fieldValue) ? json_encode($fieldValue, JSON_UNESCAPED_UNICODE) : $fieldValue; $now = date('Y-m-d H:i:s'); if ($existing) { TemplateSiteConfig::where('id', $existing['id']) ->update([ 'value' => $value, 'update_time' => $now ]); } else { TemplateSiteConfig::insert([ 'tid' => $tid, 'key' => $configKey, 'value' => $value, 'create_time' => $now, 'update_time' => $now ]); } return true; } catch (\Exception $e) { return false; } } }