star-cloud/app/Models/Machine/MachineLog.php
sky121113 acde99e383 [FIX] 修正下位機 Discord 告警發送條件與層級對等
1. 調整 MachineLog 的 created 監聽器,使 submachine 類型日誌僅在 level 為 warning 或 error 時才派發 Discord 通知任務,避免 info 狀態日誌(如出貨中、平台上升中)洗板告警。
2. 優化 DiscordWebhookService 的下位機異常渲染,根據日誌嚴重程度 (level) 動態調整標題前面的 Emoji 圖示,error 級別顯示 🚨,warning 級別顯示 ⚠️
2026-05-28 14:53:06 +08:00

123 lines
4.0 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\Models\Machine;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class MachineLog extends Model
{
use HasFactory;
const UPDATED_AT = null;
protected static function booted()
{
static::created(function (MachineLog $log) {
// 1. 取得機台與公司,若無公司則直接 return
$machine = $log->machine;
if (!$machine || !$machine->company) {
return;
}
$company = $machine->company;
$companySettings = $company->settings ?? [];
// 必須啟用 Discord 通知功能
if (!($companySettings['discord_notify_enabled'] ?? false)) {
return;
}
// 優先讀取機台專屬 Webhook無則繼承公司全域 Webhook
$machineSettings = $machine->settings ?? [];
$webhookUrl = $machineSettings['discord_webhook_url'] ?? $companySettings['discord_webhook_url'] ?? null;
if (empty($webhookUrl)) {
return;
}
// 2. 判定是否符合發送條件
$shouldNotify = false;
if ($log->type === 'temperature') {
$shouldNotify = true;
} elseif ($log->type === 'status') {
if ($log->message === 'Connection lost (LWT)') {
$shouldNotify = true;
} elseif ($log->message === 'Connection restored') {
// 尋找此機台前一筆狀態日誌 (ID 比當前小type 為 status倒序第一筆)
$previousStatus = self::withoutGlobalScopes()
->where('machine_id', $log->machine_id)
->where('type', 'status')
->where('id', '<', $log->id)
->orderBy('id', 'desc')
->first();
if ($previousStatus && $previousStatus->message === 'Connection lost (LWT)' && $previousStatus->is_resolved) {
// 只有當前一筆是真實 LWT 斷線,且已被消警 (is_resolved = true) 時,才發送恢復通知
$shouldNotify = true;
}
}
} elseif ($log->type === 'submachine') {
// 下位機日誌僅在 warning 或 error 級別時發送 Discord 告警info 狀態日誌不發送
if (in_array($log->level, ['warning', 'error'])) {
$shouldNotify = true;
}
} elseif ($log->level === 'error') {
$shouldNotify = true;
}
// 3. 若符合發送條件,調度非同步任務
if ($shouldNotify) {
\App\Jobs\Notification\SendDiscordNotificationJob::dispatch($log->id);
}
});
}
protected $fillable = [
'company_id',
'machine_id',
'level',
'type',
'message',
'context',
'is_resolved',
];
protected $casts = [
'context' => 'array',
'is_resolved' => 'boolean',
];
protected $appends = [
'translated_message',
];
/**
* 動態重組翻譯後的訊息
*/
public function getTranslatedMessageAttribute(): string
{
$context = $this->context;
// 若 context 中已有翻譯標籤 (B013 封裝),則進行動態重組
if (isset($context['translated_label'])) {
$label = __($context['translated_label']);
$tid = $context['tid'] ?? null;
$code = $context['raw_code'] ?? '0000';
if ($tid) {
return __('Slot') . " {$tid}: {$label} (Code: {$code})";
}
return "{$label} (Code: {$code})";
}
// 預設退回原始 message (支援歷史資料的翻譯判定與佔位符替換)
return __($this->message, $context ?? []);
}
public function machine()
{
return $this->belongsTo(Machine::class);
}
}