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\Helper;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Foundation\Console\ConfigCacheCommand;
use Illuminate\Support\Facades\Cache;
use Matriphe\Larinfo;
@ -43,6 +45,5 @@ class Test extends Command
*/
public function handle()
{
abort(500, 123);
}
}

View File

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

View File

@ -20,6 +20,25 @@ class ThemeController extends Controller
}, 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()
{
$themeConfigs = [];
@ -28,12 +47,14 @@ class ThemeController extends Controller
if (!File::exists($themeConfigFile)) continue;
$themeConfig = include($themeConfigFile);
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([
'data' => [
'themes' => $themeConfigs,
'active' => config('v2board.theme', 'v2board')
'active' => config('v2board.frontend_theme', 'v2board')
]
]);
}
@ -52,7 +73,7 @@ class ThemeController extends Controller
{
$payload = $request->validate([
'name' => 'required|in:' . join(',', $this->themes),
'configs' => 'required|array'
'config' => 'required|array'
]);
$themeConfigFile = public_path("theme/{$payload['name']}/config.php");
if (!File::exists($themeConfigFile)) abort(500, '主题不存在');
@ -60,8 +81,7 @@ class ThemeController extends Controller
$validateFields = array_column($themeConfig['configs'], 'field_name');
$config = [];
foreach ($validateFields as $validateField) {
if (!isset($payload['configs'][$validateField])) continue;
$config[$validateField] = $payload['configs'][$validateField];
$config[$validateField] = isset($payload['config'][$validateField]) ? $payload['config'][$validateField] : '';
}
File::ensureDirectoryExists(base_path() . '/config/theme/');
@ -78,7 +98,7 @@ class ThemeController extends Controller
}
return response([
'data' => config('theme.v2board')
'data' => $config
]);
}
}

View File

@ -6,6 +6,113 @@ use Illuminate\Foundation\Http\FormRequest;
class ConfigSave extends FormRequest
{
const RULES = [
// invite & commission
'safe_mode_enable' => 'in:0,1',
'invite_force' => 'in:0,1',
'invite_commission' => 'integer',
'invite_gen_limit' => 'integer',
'invite_never_expire' => 'in:0,1',
'commission_first_time_enable' => 'in:0,1',
'commission_auto_check_enable' => 'in:0,1',
'commission_withdraw_limit' => 'nullable|numeric',
'commission_withdraw_method' => 'nullable|array',
'withdraw_close_enable' => 'in:0,1',
'commission_distribution_enable' => 'in:0,1',
'commission_distribution_l1' => 'nullable|numeric',
'commission_distribution_l2' => 'nullable|numeric',
'commission_distribution_l3' => 'nullable|numeric',
// site
'stop_register' => 'in:0,1',
'email_verify' => 'in:0,1',
'app_name' => '',
'app_description' => '',
'app_url' => 'nullable|url',
'subscribe_url' => 'nullable',
'try_out_enable' => 'in:0,1',
'try_out_plan_id' => 'integer',
'try_out_hour' => 'numeric',
'email_whitelist_enable' => 'in:0,1',
'email_whitelist_suffix' => 'nullable|array',
'email_gmail_limit_enable' => 'in:0,1',
'recaptcha_enable' => 'in:0,1',
'recaptcha_key' => '',
'recaptcha_site_key' => '',
'tos_url' => 'nullable|url',
'currency' => '',
'currency_symbol' => '',
'register_limit_by_ip_enable' => 'in:0,1',
'register_limit_count' => 'integer',
'register_limit_expire' => 'integer',
// subscribe
'plan_change_enable' => 'in:0,1',
'reset_traffic_method' => 'in:0,1,2',
'surplus_enable' => 'in:0,1',
'new_order_event_id' => 'in:0,1',
'renew_order_event_id' => 'in:0,1',
'change_order_event_id' => 'in:0,1',
// server
'server_token' => 'nullable|min:16',
'server_license' => 'nullable',
'server_log_enable' => 'in:0,1',
'server_v2ray_domain' => '',
'server_v2ray_protocol' => '',
// alipay
'alipay_enable' => 'in:0,1',
'alipay_appid' => 'nullable|integer|min:16',
'alipay_pubkey' => 'max:2048',
'alipay_privkey' => 'max:2048',
// stripe
'stripe_alipay_enable' => 'in:0,1',
'stripe_wepay_enable' => 'in:0,1',
'stripe_card_enable' => 'in:0,1',
'stripe_sk_live' => '',
'stripe_pk_live' => '',
'stripe_webhook_key' => '',
'stripe_currency' => 'in:hkd,usd,sgd,eur,gbp,jpy,cad',
// bitpayx
'bitpayx_name' => '',
'bitpayx_enable' => 'in:0,1',
'bitpayx_appsecret' => '',
// mGate
'mgate_name' => '',
'mgate_enable' => 'in:0,1',
'mgate_url' => 'nullable|url',
'mgate_app_id' => '',
'mgate_app_secret' => '',
// Epay
'epay_name' => '',
'epay_enable' => 'in:0,1',
'epay_url' => 'nullable|url',
'epay_pid' => '',
'epay_key' => '',
// frontend
'frontend_theme' => '',
'frontend_admin_path' => '',
'frontend_customer_service_method' => '',
'frontend_customer_service_id' => '',
// email
'email_template' => '',
'email_host' => '',
'email_port' => '',
'email_username' => '',
'email_password' => '',
'email_encryption' => '',
'email_from_address' => '',
// telegram
'telegram_bot_enable' => 'in:0,1',
'telegram_bot_token' => '',
'telegram_discuss_id' => '',
'telegram_channel_id' => '',
'telegram_discuss_link' => 'nullable|url',
// app
'windows_version' => '',
'windows_download_url' => '',
'macos_version' => '',
'macos_download_url' => '',
'android_version' => '',
'android_download_url' => ''
];
/**
* Get the validation rules that apply to the request.
*
@ -13,117 +120,7 @@ class ConfigSave extends FormRequest
*/
public function rules()
{
return [
// invite & commission
'safe_mode_enable' => 'in:0,1',
'invite_force' => 'in:0,1',
'invite_commission' => 'integer',
'invite_gen_limit' => 'integer',
'invite_never_expire' => 'in:0,1',
'commission_first_time_enable' => 'in:0,1',
'commission_auto_check_enable' => 'in:0,1',
'commission_withdraw_limit' => 'nullable|numeric',
'commission_withdraw_method' => 'nullable|array',
'withdraw_close_enable' => 'in:0,1',
'commission_distribution_enable' => 'in:0,1',
'commission_distribution_l1' => 'nullable|numeric',
'commission_distribution_l2' => 'nullable|numeric',
'commission_distribution_l3' => 'nullable|numeric',
// site
'stop_register' => 'in:0,1',
'email_verify' => 'in:0,1',
'app_name' => '',
'app_description' => '',
'app_url' => 'nullable|url',
'subscribe_url' => 'nullable',
'try_out_enable' => 'in:0,1',
'try_out_plan_id' => 'integer',
'try_out_hour' => 'numeric',
'email_whitelist_enable' => 'in:0,1',
'email_whitelist_suffix' => 'nullable|array',
'email_gmail_limit_enable' => 'in:0,1',
'recaptcha_enable' => 'in:0,1',
'recaptcha_key' => '',
'recaptcha_site_key' => '',
'tos_url' => 'nullable|url',
'currency' => '',
'currency_symbol' => '',
'register_limit_by_ip_enable' => 'in:0,1',
'register_limit_count' => 'integer',
'register_limit_expire' => 'integer',
// subscribe
'plan_change_enable' => 'in:0,1',
'reset_traffic_method' => 'in:0,1,2',
'surplus_enable' => 'in:0,1',
'new_order_event_id' => 'in:0,1',
'renew_order_event_id' => 'in:0,1',
'change_order_event_id' => 'in:0,1',
// server
'server_token' => 'nullable|min:16',
'server_license' => 'nullable',
'server_log_enable' => 'in:0,1',
'server_v2ray_domain' => '',
'server_v2ray_protocol' => '',
// alipay
'alipay_enable' => 'in:0,1',
'alipay_appid' => 'nullable|integer|min:16',
'alipay_pubkey' => 'max:2048',
'alipay_privkey' => 'max:2048',
// stripe
'stripe_alipay_enable' => 'in:0,1',
'stripe_wepay_enable' => 'in:0,1',
'stripe_card_enable' => 'in:0,1',
'stripe_sk_live' => '',
'stripe_pk_live' => '',
'stripe_webhook_key' => '',
'stripe_currency' => 'in:hkd,usd,sgd,eur,gbp,jpy,cad',
// bitpayx
'bitpayx_name' => '',
'bitpayx_enable' => 'in:0,1',
'bitpayx_appsecret' => '',
// mGate
'mgate_name' => '',
'mgate_enable' => 'in:0,1',
'mgate_url' => 'nullable|url',
'mgate_app_id' => '',
'mgate_app_secret' => '',
// Epay
'epay_name' => '',
'epay_enable' => 'in:0,1',
'epay_url' => 'nullable|url',
'epay_pid' => '',
'epay_key' => '',
// frontend
'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_customer_service_method' => '',
'frontend_customer_service_id' => '',
// email
'email_template' => '',
'email_host' => '',
'email_port' => '',
'email_username' => '',
'email_password' => '',
'email_encryption' => '',
'email_from_address' => '',
// telegram
'telegram_bot_enable' => 'in:0,1',
'telegram_bot_token' => '',
'telegram_discuss_id' => '',
'telegram_channel_id' => '',
'telegram_discuss_link' => 'nullable|url',
// app
'windows_version' => '',
'windows_download_url' => '',
'macos_version' => '',
'macos_download_url' => '',
'android_version' => '',
'android_download_url' => ''
];
return self::RULES;
}
public function messages()

View File

@ -117,7 +117,7 @@ class AdminRoute
// Theme
$router->get ('/theme/getThemes', 'Admin\\ThemeController@getThemes');
$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',
'使用支持扫码的客户端进行订阅': 'Use a client app that supports scanning 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 [
'name' => 'V2board',
'description' => '这是一个描述',
'description' => 'V2board默认主题',
'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' => [
[
'field_name' => 'theme', // 字段名
'description' => '这是一个字段主题', // 描述
'field_type' => 'select', // 字段类型: select,input,switch
'select_options' => [ // [filed_type]_options
'奶绿'
]
'label' => '主题色', // 标签
'placeholder' => '请选择主题颜色', // 描述
'field_name' => 'theme_color', // 字段名 作为数据key使用
'field_type' => 'select', // 字段类型: select,input,switch
'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',
'green' => '#319795'
])
<meta name="theme-color" content="{{$colors[$theme_color]}}">
<meta name="theme-color" content="{{$colors[$theme_config['theme_color']]}}">
<title>{{$title}}</title>
<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,400i,600,700"> -->
@ -25,14 +25,13 @@
title: '{{$title}}',
theme_path: '{{$theme_path}}',
theme: {
sidebar: '{{$theme_sidebar}}',
header: '{{$theme_header}}',
color: '{{$theme_color}}',
sidebar: '{{$theme_config['theme_sidebar']}}',
header: '{{$theme_config['theme_header']}}',
color: '{{$theme_config['theme_color']}}',
},
version: '{{$version}}',
background_url: '{{$background_url}}',
background_url: '{{$theme_config['background_url']}}',
description: '{{$description}}',
crisp_id: '{{$crisp_id}}',
i18n: [
'zh-CN',
'en-US',
@ -53,6 +52,7 @@
<body>
<div id="root"></div>
{{!! $config['custom_html'] !!}}
<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/umi.js?v={{$version}}"></script>

View File

@ -23,14 +23,10 @@ Route::get('/', function (Request $request) {
'title' => config('v2board.app_name', 'V2Board'),
'theme' => config('v2board.frontend_theme', 'v2board'),
'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'),
'description' => config('v2board.app_description', 'V2Board is best'),
'crisp_id' => config('v2board.frontend_customer_service_method') === 'crisp' ? config('v2board.frontend_customer_service_id') : ''
'description' => config('v2board.app_description', 'V2Board is best')
];
$renderParams['theme_config'] = config('theme.' . config('v2board.frontend_theme', 'v2board'));
return view('theme::' . config('v2board.frontend_theme', 'v2board') . '.dashboard', $renderParams);
});