Files
KnowledgeBase/resources/views/filament/infolists/components/activity-log-diff.blade.php
lizhuoran b9c897cd64 feat: 实现操作日志管理界面
- ActivityLogResource: Filament 资源类
  - 只读模式(禁用创建、编辑、删除)
  - 表格列:时间、用户、操作类型、对象、详情
  - 按时间倒序排序
  - 支持多维度筛选(时间范围、操作类型、用户、对象类型)
  - 集成导出功能(Excel/CSV)

- ViewActivityLog: 日志详情页面
  - 完整的变更信息展示
  - JSON diff 对比视图
  - 支持查看原始 JSON 数据

- activity-log-diff.blade.php: Diff 对比组件
  - 字段级别的变更对比
  - 使用颜色区分新旧值(绿色/红色)
  - 支持 JSON 数据格式化显示
2026-03-09 10:08:44 +08:00

104 lines
6.0 KiB
PHP

<div class="space-y-4">
@php
$properties = $getState();
$old = $properties['old'] ?? [];
$attributes = $properties['attributes'] ?? [];
// 获取所有键
$allKeys = array_unique(array_merge(array_keys($old), array_keys($attributes)));
@endphp
@if(empty($allKeys))
<div class="text-sm text-gray-500 dark:text-gray-400">
无变更数据
</div>
@else
<div class="overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-800">
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-1/4">
字段
</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-3/8">
旧值
</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-3/8">
新值
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">
@foreach($allKeys as $key)
@php
$oldValue = $old[$key] ?? null;
$newValue = $attributes[$key] ?? null;
$hasChanged = $oldValue !== $newValue;
@endphp
<tr class="{{ $hasChanged ? 'bg-yellow-50 dark:bg-yellow-900/10' : '' }}">
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-gray-100">
{{ $key }}
@if($hasChanged)
<span class="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200">
已变更
</span>
@endif
</td>
<td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
@if($oldValue !== null)
<div class="font-mono text-xs bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300 p-2 rounded border border-red-200 dark:border-red-800">
@if(is_array($oldValue) || is_object($oldValue))
<pre class="whitespace-pre-wrap break-words">{{ json_encode($oldValue, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) }}</pre>
@else
{{ $oldValue }}
@endif
</div>
@else
<span class="text-gray-400 dark:text-gray-600 italic">-</span>
@endif
</td>
<td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
@if($newValue !== null)
<div class="font-mono text-xs bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-300 p-2 rounded border border-green-200 dark:border-green-800">
@if(is_array($newValue) || is_object($newValue))
<pre class="whitespace-pre-wrap break-words">{{ json_encode($newValue, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) }}</pre>
@else
{{ $newValue }}
@endif
</div>
@else
<span class="text-gray-400 dark:text-gray-600 italic">-</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@if(!empty($old) || !empty($attributes))
<div class="mt-4 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg">
<details class="space-y-2">
<summary class="cursor-pointer text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100">
查看原始 JSON 数据
</summary>
<div class="mt-2 space-y-2">
@if(!empty($old))
<div>
<div class="text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">旧值 (JSON):</div>
<pre class="text-xs bg-white dark:bg-gray-900 p-3 rounded border border-gray-200 dark:border-gray-700 overflow-x-auto">{{ json_encode($old, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) }}</pre>
</div>
@endif
@if(!empty($attributes))
<div>
<div class="text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">新值 (JSON):</div>
<pre class="text-xs bg-white dark:bg-gray-900 p-3 rounded border border-gray-200 dark:border-gray-700 overflow-x-auto">{{ json_encode($attributes, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) }}</pre>
</div>
@endif
</div>
</details>
</div>
@endif
@endif
</div>