feat: rbac初步对接完成
This commit is contained in:
+31
-30
@@ -16,7 +16,7 @@ export default function Logs() {
|
||||
const [logs, setLogs] = useState<OperationLog[]>([])
|
||||
const [total, setTotal] = useState(0)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [search, setSearch] = useState({ operatorName: '', clientId: 'all', path: '' })
|
||||
const [search, setSearch] = useState({ path: '', method: '', status: undefined as number | undefined })
|
||||
const [pagination, setPagination] = useState({ current: 1, pageSize: 12 })
|
||||
|
||||
// Dialog State for viewing details
|
||||
@@ -27,9 +27,9 @@ export default function Logs() {
|
||||
setLoading(true)
|
||||
try {
|
||||
const res = await getLogList({ ...pagination, ...search })
|
||||
if (res.data) {
|
||||
setLogs(res.data.list)
|
||||
setTotal(res.data.total)
|
||||
if (res) {
|
||||
setLogs(res.list)
|
||||
setTotal(res.total)
|
||||
}
|
||||
} finally {
|
||||
setLoading(false)
|
||||
@@ -44,7 +44,7 @@ export default function Logs() {
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
setSearch({ operatorName: '', clientId: 'all', path: '' })
|
||||
setSearch({ path: '', method: '', status: undefined })
|
||||
if (pagination.current === 1) setTimeout(() => fetchLogs(), 0)
|
||||
else setPagination({ ...pagination, current: 1 })
|
||||
}
|
||||
@@ -79,25 +79,27 @@ export default function Logs() {
|
||||
</CardTitle>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<Select value={search.clientId} onValueChange={v => setSearch({ ...search, clientId: v })}>
|
||||
<Select value={search.method || 'all'} onValueChange={v => setSearch({ ...search, method: v === 'all' ? '' : v })}>
|
||||
<SelectTrigger className="w-[140px] h-9">
|
||||
<SelectValue placeholder="客户端来源" />
|
||||
<SelectValue placeholder="请求方法" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">所有客户端</SelectItem>
|
||||
<SelectItem value="gateway">API 网关</SelectItem>
|
||||
<SelectItem value="plant">Plant 服务</SelectItem>
|
||||
<SelectItem value="radio">Radio 服务</SelectItem>
|
||||
<SelectItem value="all">所有方法</SelectItem>
|
||||
<SelectItem value="GET">GET</SelectItem>
|
||||
<SelectItem value="POST">POST</SelectItem>
|
||||
<SelectItem value="PUT">PUT</SelectItem>
|
||||
<SelectItem value="DELETE">DELETE</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder="操作者账号..."
|
||||
placeholder="状态码 (如 200, 400)..."
|
||||
type="number"
|
||||
className="pl-9 w-40 h-9"
|
||||
value={search.operatorName}
|
||||
onChange={e => setSearch({ ...search, operatorName: e.target.value })}
|
||||
value={search.status || ''}
|
||||
onChange={e => setSearch({ ...search, status: e.target.value ? Number(e.target.value) : undefined })}
|
||||
onKeyDown={e => e.key === 'Enter' && handleSearch()}
|
||||
/>
|
||||
</div>
|
||||
@@ -145,10 +147,10 @@ export default function Logs() {
|
||||
) : (
|
||||
logs.map(log => (
|
||||
<TableRow key={log.id} className="hover:bg-muted/20">
|
||||
<TableCell className="font-medium pl-6">{log.operatorName || '-'}</TableCell>
|
||||
<TableCell className="font-medium pl-6">{log.userId || '-'}</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline" className="bg-primary/5 font-normal">
|
||||
{log.clientName || log.clientId || 'System'}
|
||||
{log.clientId || 'System'}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
@@ -158,29 +160,28 @@ export default function Logs() {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="font-medium text-sm">{log.title}</span>
|
||||
<span className="text-xs text-muted-foreground font-mono">{log.path}</span>
|
||||
<span className="font-medium text-sm text-muted-foreground font-mono">{log.path}</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{log.statusCode === 200 ? (
|
||||
{log.status === 200 ? (
|
||||
<div className="flex items-center text-emerald-600 text-sm">
|
||||
<Activity className="w-4 h-4 mr-1" /> 200 OK
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center text-red-500 text-sm font-medium">
|
||||
<AlertCircle className="w-4 h-4 mr-1" /> {log.statusCode}
|
||||
<AlertCircle className="w-4 h-4 mr-1" /> {log.status}
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className={`flex items-center text-sm font-mono ${log.duration > 200 ? 'text-amber-500 font-medium' : 'text-muted-foreground'}`}>
|
||||
<div className={`flex items-center text-sm font-mono ${log.latency > 200000000 ? 'text-amber-500 font-medium' : 'text-muted-foreground'}`}>
|
||||
<Clock className="w-3.5 h-3.5 mr-1.5 opacity-70" />
|
||||
{log.duration}ms
|
||||
{(log.latency / 1000000).toFixed(0)}ms
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-muted-foreground text-sm font-mono">
|
||||
{new Date(log.createdAt).toLocaleString('zh-CN')}
|
||||
{new Date(log.createdAt * 1000).toLocaleString('zh-CN')}
|
||||
</TableCell>
|
||||
<TableCell className="text-right pr-6">
|
||||
<Button variant="ghost" size="sm" className="h-8 w-8 p-0 text-blue-500" onClick={() => openDetail(log)}>
|
||||
@@ -232,29 +233,29 @@ export default function Logs() {
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4 p-4 rounded-lg bg-muted/30 border border-border/50 text-sm">
|
||||
<div><span className="text-muted-foreground inline-block w-20">接口路径:</span> <span className="font-mono font-medium">{activeLog.path}</span></div>
|
||||
<div><span className="text-muted-foreground inline-block w-20">操作者:</span> <span className="font-medium">{activeLog.operatorName}</span></div>
|
||||
<div><span className="text-muted-foreground inline-block w-20">客户端:</span> {activeLog.clientName}</div>
|
||||
<div><span className="text-muted-foreground inline-block w-20">操作者ID:</span> <span className="font-medium">{activeLog.userId}</span></div>
|
||||
<div><span className="text-muted-foreground inline-block w-20">客户端:</span> {activeLog.clientId}</div>
|
||||
<div><span className="text-muted-foreground inline-block w-20">IP地址:</span> <span className="font-mono">{activeLog.ip}</span></div>
|
||||
<div className="col-span-2"><span className="text-muted-foreground inline-block w-20">User-Agent:</span> <span className="text-xs text-muted-foreground">{activeLog.userAgent}</span></div>
|
||||
<div className="col-span-2"><span className="text-muted-foreground inline-block w-20">User-Agent:</span> <span className="text-xs text-muted-foreground">{activeLog.agent}</span></div>
|
||||
</div>
|
||||
|
||||
{activeLog.requestBody && (
|
||||
{activeLog.body && (
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-sm font-semibold flex items-center gap-2"><Activity className="w-4 h-4" /> Request Payload</h4>
|
||||
<ScrollArea className="h-[120px] w-full rounded-md border bg-zinc-950 p-4">
|
||||
<pre className="text-xs text-emerald-400 font-mono leading-relaxed">
|
||||
{JSON.stringify(JSON.parse(activeLog.requestBody), null, 2)}
|
||||
{JSON.stringify(JSON.parse(activeLog.body), null, 2)}
|
||||
</pre>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeLog.responseBody && (
|
||||
{activeLog.resp && (
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-sm font-semibold flex items-center gap-2"><Activity className="w-4 h-4" /> Response Data</h4>
|
||||
<ScrollArea className="h-[150px] w-full rounded-md border bg-zinc-950 p-4">
|
||||
<pre className="text-xs text-blue-400 font-mono leading-relaxed">
|
||||
{JSON.stringify(JSON.parse(activeLog.responseBody), null, 2)}
|
||||
{JSON.stringify(JSON.parse(activeLog.resp), null, 2)}
|
||||
</pre>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user