175 lines
5.0 KiB
PHP
175 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace app\support;
|
|
|
|
use support\think\Db;
|
|
|
|
class MessageDispatcher
|
|
{
|
|
public function sendInboxEvent(string $eventCode, array $context): bool
|
|
{
|
|
$userId = (int)($context['user_id'] ?? 0);
|
|
$bizType = trim((string)($context['biz_type'] ?? ''));
|
|
$bizId = (int)($context['biz_id'] ?? 0);
|
|
|
|
if ($userId <= 0 || $bizType === '' || $bizId <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (!$this->shouldSendByPreference($userId, $eventCode)) {
|
|
return false;
|
|
}
|
|
|
|
$rule = Db::name('message_rules')
|
|
->where('event_code', $eventCode)
|
|
->where('channel', 'inbox')
|
|
->where('is_enabled', 1)
|
|
->order('id', 'asc')
|
|
->find();
|
|
|
|
if (!$rule) {
|
|
$disabledRule = Db::name('message_rules')
|
|
->where('event_code', $eventCode)
|
|
->where('channel', 'inbox')
|
|
->find();
|
|
|
|
if ($disabledRule) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$template = null;
|
|
if ($rule) {
|
|
$template = Db::name('message_templates')
|
|
->where('id', (int)$rule['template_id'])
|
|
->where('channel', 'inbox')
|
|
->where('is_enabled', 1)
|
|
->find();
|
|
}
|
|
|
|
$alreadySent = Db::name('message_logs')
|
|
->where('user_id', $userId)
|
|
->where('biz_type', $bizType)
|
|
->where('biz_id', $bizId)
|
|
->where('channel', 'inbox')
|
|
->where('status', 'sent')
|
|
->find();
|
|
|
|
if ($alreadySent) {
|
|
return false;
|
|
}
|
|
|
|
$title = $this->renderTemplate(
|
|
$template['title'] ?? (string)($context['fallback_title'] ?? ''),
|
|
$context
|
|
);
|
|
$content = $this->renderTemplate(
|
|
$template['content'] ?? (string)($context['fallback_content'] ?? ''),
|
|
$context
|
|
);
|
|
|
|
if ($title === '' && $content === '') {
|
|
return false;
|
|
}
|
|
|
|
$now = date('Y-m-d H:i:s');
|
|
|
|
Db::name('user_messages')->insert([
|
|
'user_id' => $userId,
|
|
'title' => $title !== '' ? $title : '系统通知',
|
|
'content' => $content,
|
|
'biz_type' => $bizType,
|
|
'biz_id' => $bizId,
|
|
'is_read' => 0,
|
|
'read_at' => null,
|
|
'created_at' => $now,
|
|
'updated_at' => $now,
|
|
]);
|
|
|
|
Db::name('message_logs')->insert([
|
|
'user_id' => $userId,
|
|
'template_id' => $template['id'] ?? null,
|
|
'biz_type' => $bizType,
|
|
'biz_id' => $bizId,
|
|
'channel' => 'inbox',
|
|
'status' => 'sent',
|
|
'fail_reason' => '',
|
|
'sent_at' => $now,
|
|
'created_at' => $now,
|
|
'updated_at' => $now,
|
|
]);
|
|
|
|
return true;
|
|
}
|
|
|
|
private function shouldSendByPreference(int $userId, string $eventCode): bool
|
|
{
|
|
$preferenceKey = $this->preferenceKeyForEvent($eventCode);
|
|
if ($preferenceKey === '') {
|
|
return true;
|
|
}
|
|
|
|
$configValue = Db::name('system_configs')
|
|
->where('config_group', 'user_settings')
|
|
->where('config_key', 'user_' . $userId)
|
|
->value('config_value');
|
|
|
|
if (!is_string($configValue) || $configValue === '') {
|
|
return $this->defaultPreference($preferenceKey);
|
|
}
|
|
|
|
$decoded = json_decode($configValue, true);
|
|
if (!is_array($decoded)) {
|
|
return $this->defaultPreference($preferenceKey);
|
|
}
|
|
|
|
if (!array_key_exists($preferenceKey, $decoded)) {
|
|
return $this->defaultPreference($preferenceKey);
|
|
}
|
|
|
|
return (bool)$decoded[$preferenceKey];
|
|
}
|
|
|
|
private function preferenceKeyForEvent(string $eventCode): string
|
|
{
|
|
return match ($eventCode) {
|
|
'order_created' => 'notify_order',
|
|
'return_shipped' => 'notify_order',
|
|
'return_received' => 'notify_order',
|
|
'report_published' => 'notify_report',
|
|
'supplement_required' => 'notify_supplement',
|
|
'ticket_reply', 'ticket_waiting_user', 'ticket_resolved', 'ticket_closed' => 'notify_ticket',
|
|
default => '',
|
|
};
|
|
}
|
|
|
|
private function defaultPreference(string $key): bool
|
|
{
|
|
return match ($key) {
|
|
'marketing_notify', 'privacy_mode' => false,
|
|
default => true,
|
|
};
|
|
}
|
|
|
|
private function renderTemplate(string $text, array $context): string
|
|
{
|
|
if ($text === '') {
|
|
return '';
|
|
}
|
|
|
|
return preg_replace_callback('/\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/', function (array $matches) use ($context) {
|
|
$key = $matches[1];
|
|
if (!array_key_exists($key, $context)) {
|
|
return '';
|
|
}
|
|
|
|
$value = $context[$key];
|
|
if (is_scalar($value) || $value === null) {
|
|
return (string)$value;
|
|
}
|
|
|
|
return '';
|
|
}, $text) ?? $text;
|
|
}
|
|
}
|