[FEAT] 新增機台系統日誌列表與極簡奢華風 UI
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 44s
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 44s
This commit is contained in:
@@ -34,4 +34,56 @@ class MachineController extends AdminController
|
||||
|
||||
return view('admin.machines.show', compact('machine'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 顯示所有機台日誌列表
|
||||
*/
|
||||
public function logs(Request $request): View
|
||||
{
|
||||
$logs = \App\Models\Machine\MachineLog::with('machine')
|
||||
->when($request->level, function ($query, $level) {
|
||||
return $query->where('level', $level);
|
||||
})
|
||||
->when($request->machine_id, function ($query, $machineId) {
|
||||
return $query->where('machine_id', $machineId);
|
||||
})
|
||||
->latest()
|
||||
->paginate(20);
|
||||
|
||||
$machines = Machine::select('id', 'name')->get();
|
||||
|
||||
return view('admin.machines.logs', compact('logs', 'machines'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 機台權限設定 (開發中)
|
||||
*/
|
||||
public function permissions(Request $request): View
|
||||
{
|
||||
return view('admin.machines.index', ['machines' => Machine::paginate(1)]); // Placeholder
|
||||
}
|
||||
|
||||
/**
|
||||
* 機台使用率統計 (開發中)
|
||||
*/
|
||||
public function utilization(Request $request): View
|
||||
{
|
||||
return view('admin.machines.index', ['machines' => Machine::paginate(1)]); // Placeholder
|
||||
}
|
||||
|
||||
/**
|
||||
* 機台到期管理 (開發中)
|
||||
*/
|
||||
public function expiry(Request $request): View
|
||||
{
|
||||
return view('admin.machines.index', ['machines' => Machine::paginate(1)]); // Placeholder
|
||||
}
|
||||
|
||||
/**
|
||||
* 機台維護紀錄 (開發中)
|
||||
*/
|
||||
public function maintenance(Request $request): View
|
||||
{
|
||||
return view('admin.machines.index', ['machines' => Machine::paginate(1)]); // Placeholder
|
||||
}
|
||||
}
|
||||
|
||||
11
app/Http/Controllers/Api/V1/MemberController.php
Normal file
11
app/Http/Controllers/Api/V1/MemberController.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MemberController extends Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
119
resources/views/admin/machines/logs.blade.php
Normal file
119
resources/views/admin/machines/logs.blade.php
Normal file
@@ -0,0 +1,119 @@
|
||||
@extends('layouts.admin')
|
||||
|
||||
@section('header')
|
||||
<div class="flex justify-between items-center">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('所有機台日誌') }}
|
||||
</h2>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
|
||||
<!-- 篩選器 -->
|
||||
<div class="luxury-card rounded-2xl p-6 animate-luxury-in">
|
||||
<div class="flex items-center gap-x-2 mb-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-slate-400">
|
||||
條件篩選
|
||||
</p>
|
||||
</div>
|
||||
<form method="GET" action="{{ route('admin.machines.logs') }}" class="flex flex-wrap gap-4 items-end">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">機台</label>
|
||||
<select name="machine_id" class="block w-48 rounded-md border-slate-300 shadow-sm focus:border-cyan-500 focus:ring focus:ring-cyan-500/20 text-sm dark:bg-slate-800 dark:border-slate-700 dark:text-white dark:focus:border-cyan-500">
|
||||
<option value="">全部機台</option>
|
||||
@foreach($machines as $machine)
|
||||
<option value="{{ $machine->id }}" {{ request('machine_id') == $machine->id ? 'selected' : '' }}>
|
||||
{{ $machine->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">層級</label>
|
||||
<select name="level" class="block w-32 rounded-md border-slate-300 shadow-sm focus:border-cyan-500 focus:ring focus:ring-cyan-500/20 text-sm dark:bg-slate-800 dark:border-slate-700 dark:text-white dark:focus:border-cyan-500">
|
||||
<option value="">全部層級</option>
|
||||
<option value="info" {{ request('level') == 'info' ? 'selected' : '' }}>Info</option>
|
||||
<option value="warning" {{ request('level') == 'warning' ? 'selected' : '' }}>Warning</option>
|
||||
<option value="error" {{ request('level') == 'error' ? 'selected' : '' }}>Error</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="submit" class="btn-luxury-primary">
|
||||
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<span>篩選</span>
|
||||
</button>
|
||||
<a href="{{ route('admin.machines.logs') }}" class="btn-luxury-ghost">
|
||||
重設
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 日誌清單 -->
|
||||
<div class="luxury-card rounded-2xl p-6 animate-luxury-in overflow-hidden" style="animation-delay: 100ms">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-lg font-bold text-slate-800 dark:text-white">系統日誌清單</h2>
|
||||
<span class="text-xs text-slate-400">所有時間為系統時區</span>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-[#0f172a]">
|
||||
<table class="min-w-full divide-y divide-slate-200 dark:divide-slate-700/50 font-mono text-xs">
|
||||
<thead class="bg-slate-50 dark:bg-slate-800/80">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left font-semibold text-slate-600 dark:text-slate-300">時間</th>
|
||||
<th class="px-4 py-3 text-left font-semibold text-slate-600 dark:text-slate-300">機台</th>
|
||||
<th class="px-4 py-3 text-left font-semibold text-slate-600 dark:text-slate-300">層級</th>
|
||||
<th class="px-4 py-3 text-left font-semibold text-slate-600 dark:text-slate-300">訊息</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-200 dark:divide-slate-700/50 bg-white dark:bg-transparent">
|
||||
@forelse ($logs as $log)
|
||||
<tr class="hover:bg-slate-50 dark:hover:bg-slate-800/50 transition-colors">
|
||||
<td class="px-4 py-3 text-slate-500 dark:text-slate-400 whitespace-nowrap">{{ $log->created_at->format('Y-m-d H:i:s') }}</td>
|
||||
<td class="px-4 py-3 text-slate-700 dark:text-slate-300 whitespace-nowrap">
|
||||
<a href="{{ route('admin.machines.show', $log->machine_id) }}" class="hover:text-cyan-600 dark:hover:text-cyan-400 underline decoration-slate-300 dark:decoration-slate-600 underline-offset-2 transition-colors">
|
||||
{{ $log->machine->name ?? '未知機台' }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
@php
|
||||
$levelClasses = [
|
||||
'info' => 'text-cyan-600 dark:text-cyan-400 bg-cyan-50 dark:bg-cyan-500/20 border-cyan-200 dark:border-cyan-500/30',
|
||||
'warning' => 'text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-500/20 border-amber-200 dark:border-amber-500/30 font-semibold',
|
||||
'error' => 'text-rose-600 dark:text-rose-400 bg-rose-50 dark:bg-rose-500/20 border-rose-200 dark:border-rose-500/30 font-bold',
|
||||
];
|
||||
@endphp
|
||||
<span class="px-2 py-0.5 rounded border {{ $levelClasses[$log->level] ?? 'text-slate-500 bg-slate-100 border-slate-200 dark:text-slate-300 dark:bg-slate-800 dark:border-slate-700' }}">
|
||||
{{ strtoupper($log->level) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-slate-700 dark:text-slate-200 max-w-xl break-words">
|
||||
{{ $log->message }}
|
||||
@if($log->context)
|
||||
<div class="text-[10px] text-slate-500 dark:text-slate-400 mt-2 max-h-24 overflow-y-auto bg-slate-100 dark:bg-[#0f172a] p-2 rounded-lg border border-slate-200 dark:border-slate-800/50 shadow-inner">
|
||||
{{ json_encode($log->context, JSON_UNESCAPED_UNICODE) }}
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="4" class="px-4 py-12 text-center text-slate-500 dark:text-slate-400 italic">暫無相關日誌</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($logs->hasPages())
|
||||
<div class="mt-6">
|
||||
{{ $logs->appends(request()->query())->links() }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -78,13 +78,8 @@
|
||||
|
||||
<!-- Form Group -->
|
||||
<div>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<label for="password" class="block text-sm mb-2 dark:text-white">密碼</label>
|
||||
@if (Route::has('password.request'))
|
||||
<a class="text-sm text-blue-600 decoration-2 hover:underline font-medium dark:text-blue-500" href="{{ route('password.request') }}">
|
||||
忘記密碼?
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
<div class="relative">
|
||||
<input type="password" id="password" name="password" class="py-3 px-4 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-slate-700 dark:text-gray-400 dark:focus:ring-gray-600" required autocomplete="current-password">
|
||||
|
||||
Reference in New Issue
Block a user