update: theme

This commit is contained in:
tokumeikoi 2022-05-09 00:26:38 +08:00
parent 8311722fda
commit db06001254
13 changed files with 230 additions and 179 deletions

View File

@ -7,6 +7,8 @@ use App\Models\User;
use App\Utils\CacheKey; use App\Utils\CacheKey;
use App\Utils\Helper; use App\Utils\Helper;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Foundation\Console\ConfigCacheCommand;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Matriphe\Larinfo; use Matriphe\Larinfo;
@ -43,6 +45,5 @@ class Test extends Command
*/ */
public function handle() public function handle()
{ {
abort(500, 123);
} }
} }

View File

@ -8,6 +8,8 @@ use App\Services\TelegramService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Utils\Dict; use App\Utils\Dict;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
class ConfigController extends Controller class ConfigController extends Controller
@ -118,10 +120,6 @@ class ConfigController extends Controller
], ],
'frontend' => [ 'frontend' => [
'frontend_theme' => config('v2board.frontend_theme', 'v2board'), 'frontend_theme' => config('v2board.frontend_theme', 'v2board'),
'frontend_theme_sidebar' => config('v2board.frontend_theme_sidebar', 'light'),
'frontend_theme_header' => config('v2board.frontend_theme_header', 'dark'),
'frontend_theme_color' => config('v2board.frontend_theme_color', 'default'),
'frontend_background_url' => config('v2board.frontend_background_url'),
'frontend_admin_path' => config('v2board.frontend_admin_path', 'admin'), 'frontend_admin_path' => config('v2board.frontend_admin_path', 'admin'),
'frontend_customer_service_method' => config('v2board.frontend_customer_service_method', 0), 'frontend_customer_service_method' => config('v2board.frontend_customer_service_method', 0),
'frontend_customer_service_id' => config('v2board.frontend_customer_service_id'), 'frontend_customer_service_id' => config('v2board.frontend_customer_service_id'),
@ -172,15 +170,18 @@ class ConfigController extends Controller
public function save(ConfigSave $request) public function save(ConfigSave $request)
{ {
$data = $request->validated(); $data = $request->validated();
$array = \Config::get('v2board'); $config = config('v2board');
foreach ($data as $k => $v) { foreach ($config as $k => $v) {
if (!in_array($k, array_keys($request->validated()))) { if (!in_array($k, array_keys(ConfigSave::RULES))) {
abort(500, '参数' . $k . '不在规则内,禁止修改'); unset($config[$k]);
continue;
} }
$array[$k] = $v; if (isset($data[$k])) {
$config[$k] = $data[$k];
} }
$data = var_export($array, 1); }
if (!\File::put(base_path() . '/config/v2board.php', "<?php\n return $data ;")) { $data = var_export($config, 1);
if (!File::put(base_path() . '/config/v2board.php', "<?php\n return $data ;")) {
abort(500, '修改失败'); abort(500, '修改失败');
} }
if (function_exists('opcache_reset')) { if (function_exists('opcache_reset')) {
@ -188,7 +189,7 @@ class ConfigController extends Controller
abort(500, '缓存清除失败请卸载或检查opcache配置状态'); abort(500, '缓存清除失败请卸载或检查opcache配置状态');
} }
} }
\Artisan::call('config:cache'); Artisan::call('config:cache');
return response([ return response([
'data' => true 'data' => true
]); ]);

View File

@ -20,6 +20,25 @@ class ThemeController extends Controller
}, glob($path . '*')); }, glob($path . '*'));
} }
private function initTheme($themeName, $configs)
{
$data = [];
foreach ($configs as $config) {
$data[$config['field_name']] = isset($config['default_value']) ? $config['default_value'] : '';
}
$data = var_export($data, 1);
if (!File::put(base_path() . "/config/theme/{$themeName}.php", "<?php\n return $data ;")) {
abort(500, "{$themeName}初始化失败");
}
try {
Artisan::call('config:cache');
} catch (\Exception $e) {
abort(500, "{$themeName}初始化失败");
}
}
public function getThemes() public function getThemes()
{ {
$themeConfigs = []; $themeConfigs = [];
@ -28,12 +47,14 @@ class ThemeController extends Controller
if (!File::exists($themeConfigFile)) continue; if (!File::exists($themeConfigFile)) continue;
$themeConfig = include($themeConfigFile); $themeConfig = include($themeConfigFile);
if (!isset($themeConfig['configs']) || !is_array($themeConfig)) continue; if (!isset($themeConfig['configs']) || !is_array($themeConfig)) continue;
$themeConfigs[$this->themes] = $themeConfig; $themeConfigs[$theme] = $themeConfig;
if (config("theme.{$theme}")) continue;
$this->initTheme($theme, $themeConfig['configs']);
} }
return response([ return response([
'data' => [ 'data' => [
'themes' => $themeConfigs, 'themes' => $themeConfigs,
'active' => config('v2board.theme', 'v2board') 'active' => config('v2board.frontend_theme', 'v2board')
] ]
]); ]);
} }
@ -52,7 +73,7 @@ class ThemeController extends Controller
{ {
$payload = $request->validate([ $payload = $request->validate([
'name' => 'required|in:' . join(',', $this->themes), 'name' => 'required|in:' . join(',', $this->themes),
'configs' => 'required|array' 'config' => 'required|array'
]); ]);
$themeConfigFile = public_path("theme/{$payload['name']}/config.php"); $themeConfigFile = public_path("theme/{$payload['name']}/config.php");
if (!File::exists($themeConfigFile)) abort(500, '主题不存在'); if (!File::exists($themeConfigFile)) abort(500, '主题不存在');
@ -60,8 +81,7 @@ class ThemeController extends Controller
$validateFields = array_column($themeConfig['configs'], 'field_name'); $validateFields = array_column($themeConfig['configs'], 'field_name');
$config = []; $config = [];
foreach ($validateFields as $validateField) { foreach ($validateFields as $validateField) {
if (!isset($payload['configs'][$validateField])) continue; $config[$validateField] = isset($payload['config'][$validateField]) ? $payload['config'][$validateField] : '';
$config[$validateField] = $payload['configs'][$validateField];
} }
File::ensureDirectoryExists(base_path() . '/config/theme/'); File::ensureDirectoryExists(base_path() . '/config/theme/');
@ -78,7 +98,7 @@ class ThemeController extends Controller
} }
return response([ return response([
'data' => config('theme.v2board') 'data' => $config
]); ]);
} }
} }

View File

@ -6,14 +6,7 @@ use Illuminate\Foundation\Http\FormRequest;
class ConfigSave extends FormRequest class ConfigSave extends FormRequest
{ {
/** const RULES = [
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
// invite & commission // invite & commission
'safe_mode_enable' => 'in:0,1', 'safe_mode_enable' => 'in:0,1',
'invite_force' => 'in:0,1', 'invite_force' => 'in:0,1',
@ -95,10 +88,6 @@ class ConfigSave extends FormRequest
'epay_key' => '', 'epay_key' => '',
// frontend // frontend
'frontend_theme' => '', 'frontend_theme' => '',
'frontend_theme_sidebar' => 'in:dark,light',
'frontend_theme_header' => 'in:dark,light',
'frontend_theme_color' => 'in:default,darkblue,black,green',
'frontend_background_url' => 'nullable|url',
'frontend_admin_path' => '', 'frontend_admin_path' => '',
'frontend_customer_service_method' => '', 'frontend_customer_service_method' => '',
'frontend_customer_service_id' => '', 'frontend_customer_service_id' => '',
@ -124,6 +113,14 @@ class ConfigSave extends FormRequest
'android_version' => '', 'android_version' => '',
'android_download_url' => '' 'android_download_url' => ''
]; ];
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return self::RULES;
} }
public function messages() public function messages()

View File

@ -117,7 +117,7 @@ class AdminRoute
// Theme // Theme
$router->get ('/theme/getThemes', 'Admin\\ThemeController@getThemes'); $router->get ('/theme/getThemes', 'Admin\\ThemeController@getThemes');
$router->post('/theme/saveThemeConfig', 'Admin\\ThemeController@saveThemeConfig'); $router->post('/theme/saveThemeConfig', 'Admin\\ThemeController@saveThemeConfig');
$router->get ('/theme/getThemeConfig', 'Admin\\ThemeController@getThemeConfig'); $router->post('/theme/getThemeConfig', 'Admin\\ThemeController@getThemeConfig');
}); });
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -252,18 +252,18 @@ window.settings.i18n['en-US'] = {
'不会使用,查看使用教程': 'I am a newbie, view the tutorial', '不会使用,查看使用教程': 'I am a newbie, view the tutorial',
'使用支持扫码的客户端进行订阅': 'Use a client app that supports scanning QR code to subscribe', '使用支持扫码的客户端进行订阅': 'Use a client app that supports scanning QR code to subscribe',
'扫描二维码订阅': 'Scan QR code to subscribe', '扫描二维码订阅': 'Scan QR code to subscribe',
'续费': '续费', '续费': 'Renewal',
'购买': '购买', '购买': 'Purchase',
'查看教程': '查看教程', '查看教程': 'View Tutorial',
'注意': '注意', '注意': 'Attention',
'你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?': '你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?', '你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?': 'You still have an unpaid order. You need to cancel it before purchasing. Are you sure you want to cancel the previous order?',
'确定取消': '确定取消', '确定取消': 'Confirm Cancel',
'返回我的订单': '返回我的订单', '返回我的订单': 'Back to My Order',
'如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗?': '如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗?', '如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗?': 'If you have already paid, canceling the order may cause the payment to fail. Are you sure you want to cancel the order?',
'选择最适合你的计划': '选择最适合你的计划', '选择最适合你的计划': 'Choose the right plan for you',
'全部': '全部', '全部': 'All',
'按周期': '按周期', '按周期': 'By Cycle',
'一次性': '一次性', '一次性': 'One Time',
'遇到问题': '遇到问题', '遇到问题': 'I have a problem',
'遇到问题可以通过工单与我们沟通': '遇到问题可以通过工单与我们沟通' '遇到问题可以通过工单与我们沟通': 'If you have any problems, you can contact us via ticket'
}; };

View File

@ -256,11 +256,11 @@ window.settings.i18n['zh-CN'] = {
'购买': '购买', '购买': '购买',
'查看教程': '查看教程', '查看教程': '查看教程',
'注意': '注意', '注意': '注意',
'你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?': '你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?', '你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?': '您还有未完成的订单,购买前需要先取消,确定要取消之前的订单吗?',
'确定取消': '确定取消', '确定取消': '确定取消',
'返回我的订单': '返回我的订单', '返回我的订单': '返回我的订单',
'如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗?': '如果已经付款,取消订单可能会导致支付失败,确定取消订单吗?', '如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗?': '如果已经付款,取消订单可能会导致支付失败,确定取消订单吗?',
'选择最适合你的计划': '选择最适合的计划', '选择最适合你的计划': '选择最适合的计划',
'全部': '全部', '全部': '全部',
'按周期': '按周期', '按周期': '按周期',
'一次性': '一次性', '一次性': '一次性',

View File

@ -252,18 +252,18 @@ window.settings.i18n['zh-TW'] = {
'不会使用,查看使用教程': '不會使用,檢視使用檔案', '不会使用,查看使用教程': '不會使用,檢視使用檔案',
'使用支持扫码的客户端进行订阅': '使用支持掃碼的客戶端進行訂閲', '使用支持扫码的客户端进行订阅': '使用支持掃碼的客戶端進行訂閲',
'扫描二维码订阅': '掃描二維碼訂閲', '扫描二维码订阅': '掃描二維碼訂閲',
'续费': '续费', '续费': '續費',
'购买': '购买', '购买': '購買',
'查看教程': '查看教程', '查看教程': '查看教程',
'注意': '注意', '注意': '注意',
'你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?': '你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?', '你还有未完成的订单,购买前需要先进行取消,确定取消先前的订单吗?': '您还有未完成的订单,购买前需要先取消,确定要取消之前的订单吗?',
'确定取消': '定取消', '确定取消': '定取消',
'返回我的订单': '返回我的订单', '返回我的订单': '返回我的訂單',
'如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗?': '如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗', '如果你已经付款,取消订单可能会导致支付失败,确定取消订单吗?': '如果您已經付款,取消訂單可能會導致支付失敗,確定要取消訂單嗎',
'选择最适合你的计划': '选择最适合你的计划', '选择最适合你的计划': '選擇最適合您的計劃',
'全部': '全部', '全部': '全部',
'按周期': '按期', '按周期': '按期',
'一次性': '一次性', '一次性': '一次性',
'遇到问题': '遇到问题', '遇到问题': '遇到問題',
'遇到问题可以通过工单与我们沟通': '遇到问题可以通过工单与我们沟通' '遇到问题可以通过工单与我们沟通': '遇到問題您可以通過工單與我們溝通'
}; };

File diff suppressed because one or more lines are too long

View File

@ -2,16 +2,52 @@
return [ return [
'name' => 'V2board', 'name' => 'V2board',
'description' => '这是一个描述', 'description' => 'V2board默认主题',
'version' => '1.5.6', 'version' => '1.5.6',
'images' => 'https://images.unsplash.com/photo-1515405295579-ba7b45403062?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2160&q=80',
'configs' => [ 'configs' => [
[ [
'field_name' => 'theme', // 字段名 'label' => '主题色', // 标签
'description' => '这是一个字段主题', // 描述 'placeholder' => '请选择主题颜色', // 描述
'field_name' => 'theme_color', // 字段名 作为数据key使用
'field_type' => 'select', // 字段类型: select,input,switch 'field_type' => 'select', // 字段类型: select,input,switch
'select_options' => [ // [filed_type]_options 'select_options' => [ // 当字段类型为select时有效
'奶绿' 'default' => '默认(蓝色)',
] 'green' => '奶绿色',
'black' => '黑色',
'darkblue' => '暗蓝色',
],
'default_value' => 'default' // 字段默认值,将会在首次进行初始化
], [
'label' => '背景',
'placeholder' => '请输入背景图片URL',
'field_name' => 'background_url',
'field_type' => 'input'
], [
'label' => '边栏风格',
'placeholder' => '请选择边栏风格',
'field_name' => 'theme_sidebar',
'field_type' => 'select',
'select_options' => [
'light' => '亮',
'dark' => '暗'
],
'default_value' => 'light'
], [
'label' => '顶部风格',
'placeholder' => '请选择顶部风格',
'field_name' => 'theme_header',
'field_type' => 'select',
'select_options' => [
'light' => '亮',
'dark' => '暗'
],
'default_value' => 'dark'
], [
'label' => '自定义页脚HTML',
'placeholder' => '可以实现客服JS代码的加入等',
'field_name' => 'custom_html',
'field_type' => 'textarea'
] ]
] ]
]; ];

View File

@ -15,7 +15,7 @@
'default' => '#0665d0', 'default' => '#0665d0',
'green' => '#319795' 'green' => '#319795'
]) ])
<meta name="theme-color" content="{{$colors[$theme_color]}}"> <meta name="theme-color" content="{{$colors[$theme_config['theme_color']]}}">
<title>{{$title}}</title> <title>{{$title}}</title>
<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,400i,600,700"> --> <!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,400i,600,700"> -->
@ -25,14 +25,13 @@
title: '{{$title}}', title: '{{$title}}',
theme_path: '{{$theme_path}}', theme_path: '{{$theme_path}}',
theme: { theme: {
sidebar: '{{$theme_sidebar}}', sidebar: '{{$theme_config['theme_sidebar']}}',
header: '{{$theme_header}}', header: '{{$theme_config['theme_header']}}',
color: '{{$theme_color}}', color: '{{$theme_config['theme_color']}}',
}, },
version: '{{$version}}', version: '{{$version}}',
background_url: '{{$background_url}}', background_url: '{{$theme_config['background_url']}}',
description: '{{$description}}', description: '{{$description}}',
crisp_id: '{{$crisp_id}}',
i18n: [ i18n: [
'zh-CN', 'zh-CN',
'en-US', 'en-US',
@ -53,6 +52,7 @@
<body> <body>
<div id="root"></div> <div id="root"></div>
{{!! $config['custom_html'] !!}}
<script src="/theme/{{$theme}}/assets/vendors.async.js?v={{$version}}"></script> <script src="/theme/{{$theme}}/assets/vendors.async.js?v={{$version}}"></script>
<script src="/theme/{{$theme}}/assets/components.async.js?v={{$version}}"></script> <script src="/theme/{{$theme}}/assets/components.async.js?v={{$version}}"></script>
<script src="/theme/{{$theme}}/assets/umi.js?v={{$version}}"></script> <script src="/theme/{{$theme}}/assets/umi.js?v={{$version}}"></script>

View File

@ -23,14 +23,10 @@ Route::get('/', function (Request $request) {
'title' => config('v2board.app_name', 'V2Board'), 'title' => config('v2board.app_name', 'V2Board'),
'theme' => config('v2board.frontend_theme', 'v2board'), 'theme' => config('v2board.frontend_theme', 'v2board'),
'theme_path' => '/theme/' . config('v2board.frontend_theme', 'v2board') . '/assets/', 'theme_path' => '/theme/' . config('v2board.frontend_theme', 'v2board') . '/assets/',
'theme_sidebar' => config('v2board.frontend_theme_sidebar', 'light'),
'theme_header' => config('v2board.frontend_theme_header', 'dark'),
'theme_color' => config('v2board.frontend_theme_color', 'default'),
'background_url' => config('v2board.frontend_background_url'),
'version' => config('app.version'), 'version' => config('app.version'),
'description' => config('v2board.app_description', 'V2Board is best'), 'description' => config('v2board.app_description', 'V2Board is best')
'crisp_id' => config('v2board.frontend_customer_service_method') === 'crisp' ? config('v2board.frontend_customer_service_id') : ''
]; ];
$renderParams['theme_config'] = config('theme.' . config('v2board.frontend_theme', 'v2board'));
return view('theme::' . config('v2board.frontend_theme', 'v2board') . '.dashboard', $renderParams); return view('theme::' . config('v2board.frontend_theme', 'v2board') . '.dashboard', $renderParams);
}); });