Files
MyGoNavi/frontend/src/components/LogPanel.tsx
Syngnat 027115ab87 🔧 fix(appearance): 修复透明通透失效并统一 Win/Mac 视觉强度
- 新增 macOS 原生窗口通透补强与启动重试,修复偶发不生效
- 引入跨平台透明/模糊映射,统一 Win/Mac 同滑块值观感
- 调整主窗口圆角与裁剪,优化整体视觉一致性
2026-02-06 11:35:16 +08:00

136 lines
5.0 KiB
TypeScript

import React, { useRef, useEffect } from 'react';
import { Table, Tag, Button, Tooltip } from 'antd';
import { ClearOutlined, CloseOutlined, CaretRightOutlined, BugOutlined } from '@ant-design/icons';
import { useStore } from '../store';
import { blurToFilter, normalizeBlurForPlatform, normalizeOpacityForPlatform } from '../utils/appearance';
interface LogPanelProps {
height: number;
onClose: () => void;
onResizeStart: (e: React.MouseEvent) => void;
}
const LogPanel: React.FC<LogPanelProps> = ({ height, onClose, onResizeStart }) => {
const sqlLogs = useStore(state => state.sqlLogs);
const clearSqlLogs = useStore(state => state.clearSqlLogs);
const theme = useStore(state => state.theme);
const appearance = useStore(state => state.appearance);
const darkMode = theme === 'dark';
const opacity = normalizeOpacityForPlatform(appearance.opacity);
const blur = normalizeBlurForPlatform(appearance.blur);
// Background Helper
const getBg = (darkHex: string) => {
if (!darkMode) return `rgba(255, 255, 255, ${opacity})`;
const hex = darkHex.replace('#', '');
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
};
const bgMain = getBg('#1f1f1f');
const bgToolbar = getBg('#2a2a2a');
const blurFilter = blurToFilter(blur);
const columns = [
{
title: 'Time',
dataIndex: 'timestamp',
width: 80,
render: (ts: number) => <span style={{ color: '#888', fontSize: '12px' }}>{new Date(ts).toLocaleTimeString()}</span>
},
{
title: 'Status',
dataIndex: 'status',
width: 70,
render: (status: string) => (
<Tag color={status === 'success' ? 'success' : 'error'} style={{ marginRight: 0 }}>
{status === 'success' ? 'OK' : 'ERR'}
</Tag>
)
},
{
title: 'Duration',
dataIndex: 'duration',
width: 70,
render: (d: number) => <span style={{ color: d > 1000 ? 'orange' : 'inherit', fontSize: '12px' }}>{d}ms</span>
},
{
title: 'SQL / Message',
dataIndex: 'sql',
render: (text: string, record: any) => (
<div style={{ fontFamily: 'monospace', wordBreak: 'break-all', fontSize: '12px', lineHeight: '1.2' }}>
<div style={{ color: darkMode ? '#a6e22e' : '#005cc5' }}>{text}</div>
{record.message && <div style={{ color: '#ff4d4f', marginTop: 2 }}>{record.message}</div>}
{record.affectedRows !== undefined && <div style={{ color: '#888', marginTop: 1 }}>Affected: {record.affectedRows}</div>}
</div>
)
}
];
return (
<div style={{
height,
borderTop: 'none',
background: bgMain,
backdropFilter: blurFilter,
WebkitBackdropFilter: blurFilter,
display: 'flex',
flexDirection: 'column',
position: 'relative',
zIndex: 100 // Ensure above other content
}}>
{/* Resize Handle */}
<div
onMouseDown={onResizeStart}
style={{
position: 'absolute',
top: -4,
left: 0,
right: 0,
height: 8,
cursor: 'row-resize',
zIndex: 10
}}
/>
{/* Toolbar */}
<div style={{
padding: '4px 8px',
borderBottom: 'none',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
height: 32
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, fontWeight: 'bold', fontSize: '12px' }}>
<BugOutlined /> SQL
</div>
<div>
<Tooltip title="清空日志">
<Button type="text" size="small" icon={<ClearOutlined />} onClick={clearSqlLogs} />
</Tooltip>
<Tooltip title="关闭面板">
<Button type="text" size="small" icon={<CloseOutlined />} onClick={onClose} />
</Tooltip>
</div>
</div>
{/* List */}
<div style={{ flex: 1, overflow: 'auto' }}>
<Table
dataSource={sqlLogs}
columns={columns}
size="small"
pagination={false}
rowKey="id"
showHeader={false}
// scroll={{ y: height - 32 }} // Let flex handle it
/>
</div>
</div>
);
};
export default LogPanel;