280 lines
7.8 KiB
PHP
280 lines
7.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\service;
|
|
|
|
use think\facade\Db;
|
|
use think\facade\Config;
|
|
|
|
/**
|
|
* 模板服务类
|
|
* 负责扫描 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 = 0): string
|
|
{
|
|
try {
|
|
$where = [['key', '=', 'current_theme'], ['delete_time', '=', null]];
|
|
if ($tid > 0) {
|
|
$where[] = ['tid', '=', $tid];
|
|
}
|
|
$config = Db::name('mete_template_site_config')
|
|
->where($where)
|
|
->find();
|
|
return $config['value'] ?? 'default';
|
|
} catch (\Exception $e) {
|
|
return 'default';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 切换当前模板
|
|
* @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 = Db::name('mete_template_site_config')
|
|
->where($where)
|
|
->find();
|
|
|
|
$now = date('Y-m-d H:i:s');
|
|
|
|
if ($config) {
|
|
Db::name('mete_template_site_config')->where('id', $config['id'])->update([
|
|
'value' => $themeKey,
|
|
'update_time' => $now
|
|
]);
|
|
} else {
|
|
Db::name('mete_template_site_config')->insert([
|
|
'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 {
|
|
$where = [['theme_key', '=', $themeKey], ['delete_time', '=', null]];
|
|
if ($tid > 0) {
|
|
$where[] = ['tid', '=', $tid];
|
|
}
|
|
$themeData = Db::name('mete_template_theme_data')
|
|
->where($where)
|
|
->select()
|
|
->toArray();
|
|
|
|
$data = [];
|
|
foreach ($themeData as $item) {
|
|
$data[$item['field_key']] = $item['field_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 {
|
|
$where = [
|
|
['theme_key', '=', $themeKey],
|
|
['field_key', '=', $fieldKey],
|
|
['delete_time', '=', null]
|
|
];
|
|
if ($tid > 0) {
|
|
$where[] = ['tid', '=', $tid];
|
|
}
|
|
$existing = Db::name('mete_template_theme_data')
|
|
->where($where)
|
|
->find();
|
|
|
|
$value = is_array($fieldValue) ? json_encode($fieldValue, JSON_UNESCAPED_UNICODE) : $fieldValue;
|
|
$now = date('Y-m-d H:i:s');
|
|
|
|
if ($existing) {
|
|
Db::name('mete_template_theme_data')
|
|
->where('id', $existing['id'])
|
|
->update([
|
|
'field_value' => $value,
|
|
'update_time' => $now
|
|
]);
|
|
} else {
|
|
Db::name('mete_template_theme_data')->insert([
|
|
'tid' => $tid,
|
|
'theme_key' => $themeKey,
|
|
'field_key' => $fieldKey,
|
|
'field_value' => $value,
|
|
'create_time' => $now,
|
|
'update_time' => $now
|
|
]);
|
|
}
|
|
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|