Files
lgp-admin-plus-api/app/Service/business/WxCardSchemeService.php
2026-08-19 08:16:49 +08:00

234 lines
8.2 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\business;
use App\BaseApp\BaseService;
use App\Models\business\WxCardSchemeModel;
use Illuminate\Support\Facades\DB;
/**
* 卡片画布方案15 套预设 + 运营另存为的自定义方案
*/
class WxCardSchemeService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->model = WxCardSchemeModel::class;
$this->selectField = [
'id', 'name', 'code', 'preview', 'is_preset', 'app_code',
'sort', 'status', 'created_at', 'updated_at',
];
$this->queryField = [
'name' => 'like',
'code' => 'like',
'app_code' => '=',
'is_preset' => '=',
'status' => '=',
];
$this->orderBy = ['name' => 'sort', 'sort' => 'asc'];
}
public function list(): array
{
$result = $this->getPageList();
$ids = array_values(array_filter(array_map(
static fn ($row) => (int) ($row['id'] ?? 0),
$result['items'] ?? []
)));
if ($ids === []) {
return $result;
}
$extras = WxCardSchemeModel::whereIn('id', $ids)->get(['id', 'layers'])->keyBy('id');
foreach ($result['items'] as &$item) {
$extra = $extras[(int) $item['id']] ?? null;
$item['layers'] = is_array($extra?->layers) ? $extra->layers : [];
}
unset($item);
return $result;
}
public function option(): mixed
{
$this->optionField = ['id', 'name', 'code', 'is_preset'];
return $this->getOption();
}
public function detail($id): mixed
{
$saved = $this->selectField;
$this->selectField = ['*'];
try {
return $this->getDetail($id);
} finally {
$this->selectField = $saved;
}
}
public function create($params): mixed
{
return $this->insert($this->normalize($params));
}
public function update($id, $params): mixed
{
$row = WxCardSchemeModel::where('id', $id)->where('deleted_at', 0)->first();
if (empty($row)) {
$this->utils->errorThrow('方案不存在');
}
// 预设只允许改 layers / name / preview不许改 code 以免小程序引用断裂
if ((int) $row['is_preset'] === 1) {
$params['code'] = $row['code'];
$params['is_preset'] = 1;
}
return $this->save($id, $this->normalize($params, (int) $id));
}
public function delete($ids): mixed
{
$hasPreset = WxCardSchemeModel::whereIn('id', (array) $ids)->where('is_preset', 1)->exists();
if ($hasPreset) {
$this->utils->errorThrow('内置预设不能删除,请另存为方案后再改');
}
return $this->del($ids);
}
/**
* 把当前图层另存为新方案(运营自由设计后的落点)
*/
public function saveAs(array $params): array
{
$name = trim((string) ($params['name'] ?? ''));
if ($name === '') {
$this->utils->errorThrow('请填写方案名称');
}
$code = trim((string) ($params['code'] ?? ''));
if ($code === '') {
$code = 'custom-' . substr(md5($name . microtime(true)), 0, 8);
}
$id = $this->insert($this->normalize([
'name' => $name,
'code' => $code,
'preview' => (string) ($params['preview'] ?? ''),
'layers' => $params['layers'] ?? [],
'is_preset' => 0,
'app_code' => (string) ($params['app_code'] ?? ''),
'sort' => (int) ($params['sort'] ?? 100),
'status' => 0,
]));
return ['id' => $id, 'code' => $code, 'name' => $name];
}
/**
* 用 config/wx_card_schemes.php 灌 30 套预设
*/
public function initPresets(bool $overwrite = false): array
{
$schema = WxTemplateSchemaService::getInstance();
$inserted = 0;
$updated = 0;
$skipped = 0;
$now = time();
DB::connection('business')->transaction(function () use ($schema, $overwrite, $now, &$inserted, &$updated, &$skipped) {
foreach ((array) config('wx_card_schemes', []) as $index => $preset) {
$code = (string) ($preset['code'] ?? '');
$name = (string) ($preset['name'] ?? '');
if ($code === '' || $name === '') {
continue;
}
$layers = $schema->sanitizeLayers($preset['layers'] ?? [], true);
$row = [
'name' => $name,
'code' => $code,
'preview' => (string) ($preset['preview'] ?? ''),
'layers' => json_encode($layers, JSON_UNESCAPED_UNICODE),
'is_preset' => 1,
'app_code' => '',
'sort' => $index,
'status' => 0,
'updated_at' => $now,
];
$exists = WxCardSchemeModel::where('code', $code)->where('app_code', '')->first();
if (!empty($exists)) {
if (!$overwrite) {
$skipped++;
continue;
}
WxCardSchemeModel::where('id', $exists['id'])->update($row);
$updated++;
continue;
}
$row['created_at'] = $now;
WxCardSchemeModel::insert($row);
$inserted++;
}
});
return ['inserted' => $inserted, 'updated' => $updated, 'skipped' => $skipped];
}
/**
* 按 code 列表取方案(主题下发用);库没有时回退到配置预设
*
* 必须是 static小程序 GET wx/theme 会调这里,不能走 getInstance()。
* 本类继承 BaseService构造函数会按后台 JWT 验 token小程序 token 会被直接拒掉。
*
* @param array<int, string> $codes
* @return array<string, array>
*/
public static function mapByCodes(array $codes): array
{
$codes = array_values(array_unique(array_filter(array_map('strval', $codes))));
if ($codes === []) {
return [];
}
$map = [];
try {
$rows = WxCardSchemeModel::whereIn('code', $codes)
->where('deleted_at', 0)
->where('status', 0)
->get(['code', 'name', 'layers', 'is_preset']);
foreach ($rows as $row) {
$map[(string) $row['code']] = [
'code' => (string) $row['code'],
'name' => (string) $row['name'],
'layers' => is_array($row['layers']) ? $row['layers'] : [],
'is_preset' => (int) $row['is_preset'],
];
}
} catch (\Throwable) {
// 表尚未建时走配置兜底,避免主题接口 500 把小程序打白
}
foreach ((array) config('wx_card_schemes', []) as $preset) {
$code = (string) ($preset['code'] ?? '');
if ($code === '' || isset($map[$code]) || !in_array($code, $codes, true)) {
continue;
}
$map[$code] = [
'code' => $code,
'name' => (string) ($preset['name'] ?? $code),
'layers' => (array) ($preset['layers'] ?? []),
'is_preset' => 1,
];
}
return $map;
}
private function normalize(array $params, int $excludeId = 0): array
{
$schema = WxTemplateSchemaService::getInstance();
if (array_key_exists('layers', $params)) {
$params['layers'] = json_encode($schema->sanitizeLayers($params['layers'], true), JSON_UNESCAPED_UNICODE);
}
if (!empty($params['code'])) {
$duplicate = WxCardSchemeModel::where('code', $params['code'])
->where('app_code', (string) ($params['app_code'] ?? ''))
->when($excludeId > 0, fn ($query) => $query->where('id', '!=', $excludeId))
->exists();
if ($duplicate) {
$this->utils->errorThrow('方案标识已存在');
}
}
return $params;
}
}