tp/app/service/ThemeService.php

271 lines
7.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace app\service;
use think\facade\Db;
use think\facade\Config;
use app\model\Cms\TemplateSiteConfig;
/**
* 模板服务类
* 负责扫描 public/themes 目录,管理模板配置
*/
class ThemeService
{
private string $themesPath;
public function __construct()
{
$this->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;
}
}
}