Files
lgp-admin-plus-api/app/Service/wx/WxThemeService.php
2026-08-20 19:16:49 +08:00

182 lines
6.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
namespace App\Service\wx;
use App\BaseApp\BaseWxService;
use App\Models\business\WxTemplateModel;
use App\Models\business\WxUserModel;
use App\Models\WxAppModel;
use App\Service\business\WxCardSchemeService;
use App\Service\business\WxTemplatePresetService;
use App\Service\business\WxTemplateSchemaService;
/**
* 小程序主题下发(免授权)
*
* 小程序启动时拉一次并缓存本地,拿不到就用内置兜底主题——
* 主题接口挂了不能导致小程序白屏。
*/
class WxThemeService extends BaseWxService
{
protected bool $needLogin = false;
/**
* 当前生效主题
*
* 优先级:显式 code > 登录经销商专属 template_code > 品牌配置 template_code
* > 该品牌默认模板 > 通用默认模板 > 内置预设
*/
public function current(string $code = ''): array
{
$appCode = WxAppService::getInstance()->currentCode();
$template = null;
if ($code !== '') {
$template = WxTemplateModel::where('code', $code)->where('deleted_at', 0)->where('status', 0)->first();
}
// 已登录经销商:可用专属模板覆盖品牌默认(未登录则 userInfo 为空,跳过)
if (empty($template) && (int) ($this->userInfo['is_p'] ?? 0) === 1) {
$userCode = trim((string) ($this->userInfo['template_code'] ?? ''));
if ($userCode === '' && !empty($this->userInfo['id'])) {
$userCode = (string) (WxUserModel::where('id', $this->userInfo['id'])
->where('deleted_at', 0)
->value('template_code') ?? '');
}
if ($userCode !== '') {
$template = WxTemplateModel::where('code', $userCode)
->where('deleted_at', 0)->where('status', 0)->first();
}
}
if (empty($template) && $appCode !== '') {
$bound = (string) (WxAppModel::where('code', $appCode)
->where('deleted_at', 0)
->value('template_code') ?? '');
if ($bound !== '') {
$template = WxTemplateModel::where('code', $bound)->where('deleted_at', 0)->where('status', 0)->first();
}
}
if (empty($template) && $appCode !== '') {
$template = WxTemplateModel::where('app_code', $appCode)
->where('is_default', 1)->where('deleted_at', 0)->where('status', 0)->first();
}
if (empty($template)) {
$template = WxTemplateModel::where('app_code', '')
->where('is_default', 1)->where('deleted_at', 0)->where('status', 0)->first();
}
$schema = WxTemplateSchemaService::getInstance();
if (empty($template)) {
$preset = WxTemplatePresetService::getInstance()->all()[0] ?? [];
$tokens = $preset['tokens'] ?? [];
$layout = $preset['layout'] ?? [];
return $this->packTheme(
(string) ($preset['code'] ?? 'lux-champagne'),
(string) ($preset['name'] ?? '轻奢·香槟金'),
(string) ($preset['style_tag'] ?? '轻奢'),
0,
$tokens,
$layout,
$schema,
true,
);
}
$template = $template->toArray();
$tokens = is_array($template['tokens']) ? $template['tokens'] : [];
$layout = is_array($template['layout']) ? $template['layout'] : [];
return $this->packTheme(
(string) $template['code'],
(string) $template['name'],
(string) $template['style_tag'],
(int) $template['version'],
$tokens,
$layout,
$schema,
false,
);
}
/**
* 组装主题包:令牌 + 布局 + 本模板引用到的卡片方案
*/
private function packTheme(
string $code,
string $name,
string $styleTag,
int $version,
array $tokens,
array $layout,
WxTemplateSchemaService $schema,
bool $fallback,
): array {
return [
'code' => $code,
'name' => $name,
'style_tag' => $styleTag,
'version' => $version,
'tokens' => $tokens,
'layout' => $layout,
'css_vars' => $schema->toCssVariables($tokens),
'card_schemes' => WxCardSchemeService::mapByCodes($this->collectSchemeCodes($layout)),
'features' => [
'package_enabled' => WxAppService::getInstance()->packageEnabled(),
'subscribe_pay_tpl' => $this->subscribeTpl('subscribe_pay_tpl'),
'subscribe_ship_tpl' => $this->subscribeTpl('subscribe_ship_tpl'),
],
'fallback' => $fallback,
];
}
/**
* 从根 card_scheme、页级 pages.*.card_scheme、区块 props.card_scheme 收集引用
*
* @return array<int, string>
*/
private function collectSchemeCodes(array $layout): array
{
$codes = [];
if (!empty($layout['card_scheme'])) {
$codes[] = (string) $layout['card_scheme'];
}
foreach ((array) ($layout['pages'] ?? []) as $page) {
$pageScheme = (string) ($page['card_scheme'] ?? '');
if ($pageScheme !== '') {
$codes[] = $pageScheme;
}
foreach ((array) ($page['sections'] ?? []) as $section) {
$code = (string) ($section['props']['card_scheme'] ?? '');
if ($code !== '') {
$codes[] = $code;
}
}
}
return $codes;
}
/**
* 可选风格列表,用于小程序里让用户自己换肤
*/
public function gallery(): mixed
{
$appCode = WxAppService::getInstance()->currentCode();
return WxTemplateModel::where('deleted_at', 0)
->where('status', 0)
->when($appCode !== '', fn ($query) => $query->whereIn('app_code', ['', $appCode]))
->orderBy('sort', 'asc')
->get(['code', 'name', 'style_tag', 'preview']);
}
/**
* 当前品牌的订阅模板 ID给小程序 requestSubscribeMessage 用
*/
private function subscribeTpl(string $field): string
{
try {
$app = WxAppService::getInstance()->current();
return trim((string) ($app[$field] ?? ''));
} catch (\Throwable) {
return '';
}
}
}