- 店铺主体商标数据逻辑配置新增编辑页:多商标分隔符、同日主体冲突口径、 商标号缺失处理、爬虫断更开关与天数、四类预警责任人 - 店铺维度报表逻辑配置新增期初数据编辑页:114 家变更店铺可增删改, 期初生效日随设置保存 - 规则与期初数据改存系统库 settings(扁平键),首次打开自动从 config/store_report_initial_periods.php 固化,之后不再依赖代码文件 - 控制台任务通过 bootCompanyContext() 读取同一份公司级配置 - 新增迁移清理早期嵌套设置键 - 新增 2 个测试覆盖配置保存与期初店铺增删
136 lines
4.5 KiB
PHP
136 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace Modules\EcommerceFinance\Services;
|
|
|
|
use Modules\EcommerceFinance\Services\CrawlerDataGuard;
|
|
|
|
/**
|
|
* 「店铺主体商标数据逻辑配置」的可维护参数。
|
|
*
|
|
* 页面展示的规则目录仍由 ShopEntityTrademarkLogic 维护;这里保存负责人
|
|
* 可以调整的运行参数,读取时以设置值优先、代码默认值兜底。
|
|
*/
|
|
class DataLogicSettings
|
|
{
|
|
private const PREFIX = 'business_data_logic';
|
|
|
|
/** 扁平键:设置组件会按点号展开存储,不能嵌套数组。 */
|
|
public const KEYS = [
|
|
'crawl_priority' => self::PREFIX . '.crawl_priority',
|
|
'trademark_separator' => self::PREFIX . '.trademark_separator',
|
|
'same_day_conflict_policy' => self::PREFIX . '.same_day_conflict_policy',
|
|
'missing_trademark_action' => self::PREFIX . '.missing_trademark_action',
|
|
'stale_warning_enabled' => self::PREFIX . '.stale_warning_enabled',
|
|
'stale_after_days' => self::PREFIX . '.stale_after_days',
|
|
'owner_stale' => self::PREFIX . '.owner.stale',
|
|
'owner_subject_name' => self::PREFIX . '.owner.subject_name',
|
|
'owner_subject_conflict' => self::PREFIX . '.owner.subject_conflict',
|
|
'owner_trademark' => self::PREFIX . '.owner.trademark',
|
|
];
|
|
|
|
/**
|
|
* @return array<string,mixed>
|
|
*/
|
|
public static function defaults(): array
|
|
{
|
|
return [
|
|
'crawl_priority' => '1',
|
|
'trademark_separator' => '、',
|
|
'same_day_conflict_policy' => 'crawl_wins',
|
|
'missing_trademark_action' => 'warn_keep',
|
|
'stale_warning_enabled' => '1',
|
|
'stale_after_days' => '1',
|
|
'owner_stale' => '',
|
|
'owner_subject_name' => '',
|
|
'owner_subject_conflict' => '',
|
|
'owner_trademark' => '',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string,mixed>
|
|
*/
|
|
public static function current(): array
|
|
{
|
|
$values = [];
|
|
foreach (self::KEYS as $key => $settingKey) {
|
|
$value = setting($settingKey, null);
|
|
$values[$key] = is_array($value) ? implode('', $value) : (string) ($value ?? '');
|
|
}
|
|
|
|
return array_merge(self::defaults(), array_filter($values, static fn (string $value): bool => $value !== ''));
|
|
}
|
|
|
|
public static function value(string $key, mixed $default = null): mixed
|
|
{
|
|
$current = self::current();
|
|
|
|
return $current[$key] ?? ($default ?? (self::defaults()[$key] ?? null));
|
|
}
|
|
|
|
/** @param array<string,mixed> $values */
|
|
public static function save(array $values): void
|
|
{
|
|
$payload = [];
|
|
foreach (self::defaults() as $key => $default) {
|
|
if (! array_key_exists($key, $values) || ! isset(self::KEYS[$key])) {
|
|
continue;
|
|
}
|
|
$payload[self::KEYS[$key]] = mb_substr(trim((string) $values[$key]), 0, 191);
|
|
}
|
|
|
|
if ($payload !== []) {
|
|
setting($payload)->save();
|
|
}
|
|
}
|
|
|
|
public static function separator(): string
|
|
{
|
|
$value = trim((string) self::value('trademark_separator', '、'));
|
|
|
|
return $value === '' ? '、' : $value;
|
|
}
|
|
|
|
public static function crawlWinsOnConflict(): bool
|
|
{
|
|
return (string) self::value('same_day_conflict_policy', 'crawl_wins') === 'crawl_wins';
|
|
}
|
|
|
|
public static function staleWarningEnabled(): bool
|
|
{
|
|
return (string) self::value('stale_warning_enabled', '1') === '1';
|
|
}
|
|
|
|
public static function staleAfterDays(): int
|
|
{
|
|
return max((int) self::value('stale_after_days', 1), 1);
|
|
}
|
|
|
|
public static function ownerFor(string $warningType): string
|
|
{
|
|
$map = [
|
|
CrawlerDataGuard::TYPE_STALE => 'owner_stale',
|
|
CrawlerDataGuard::TYPE_SUBJECT_NAME => 'owner_subject_name',
|
|
CrawlerDataGuard::TYPE_SUBJECT_CONFLICT => 'owner_subject_conflict',
|
|
CrawlerDataGuard::TYPE_TRADEMARK_MISSING => 'owner_trademark',
|
|
];
|
|
$key = $map[$warningType] ?? null;
|
|
|
|
return $key === null ? '' : trim((string) self::value($key, ''));
|
|
}
|
|
|
|
/**
|
|
* 控制台命令没有公司上下文,设置组件默认按 company_id = null 读取。
|
|
* 这里切到第一个公司,保证命令和网页读到同一份配置。
|
|
*/
|
|
public static function bootCompanyContext(): void
|
|
{
|
|
try {
|
|
$company = \App\Models\Common\Company::query()->orderBy('id')->first();
|
|
$company?->makeCurrent();
|
|
} catch (\Throwable) {
|
|
// 读取失败时保持原上下文,使用代码默认值。
|
|
}
|
|
}
|
|
}
|