fix: 修复proxy_service和account_service中不当的顶层import

- proxy_service.py: 将requests和WhitelistManager改为函数内延迟import,
  避免启动时加载不需要的依赖;移除未使用的get_exit_ip_via_proxy导入
- account_service.py: 移除未使用的func、joinedload、AuditLog、
  user_has_permission顶层导入
This commit is contained in:
yml2213
2026-06-23 08:35:29 +08:00
parent 2ab6724543
commit dd56de9bd4
40 changed files with 2006 additions and 936 deletions
@@ -0,0 +1,112 @@
import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react';
import { Card, Spin, Tag, theme } from 'antd';
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import type { RealtimeLog } from '../hooks/useWebSocketLogs';
interface RealtimeLogPanelProps {
logs: RealtimeLog[];
connected?: boolean;
title?: string;
emptyText?: ReactNode;
height?: number | string;
mode?: 'inline' | 'card';
collapsible?: boolean;
defaultVisible?: boolean;
spinWhenEmpty?: boolean;
style?: CSSProperties;
bodyStyle?: CSSProperties;
}
export default function RealtimeLogPanel({
logs,
connected = false,
title = '实时日志',
emptyText = '暂无日志',
height = '20vh',
mode = 'inline',
collapsible = false,
defaultVisible = true,
spinWhenEmpty = false,
style,
bodyStyle,
}: RealtimeLogPanelProps) {
const { token } = theme.useToken();
const [visible, setVisible] = useState(defaultVisible);
const endRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (visible) {
endRef.current?.scrollIntoView({ behavior: 'smooth' });
}
}, [logs, visible]);
const logColors: Record<string, string> = {
error: token.colorError,
success: token.colorSuccess,
warning: token.colorWarning,
info: token.colorText,
};
const logBody = (
<div
style={{
height,
overflow: 'auto',
fontFamily: 'monospace',
fontSize: 12,
padding: mode === 'card' ? '8px 16px' : 4,
backgroundColor: mode === 'card' ? undefined : token.colorBgLayout,
borderRadius: mode === 'card' ? undefined : 4,
...bodyStyle,
}}
>
{logs.length === 0 ? (
spinWhenEmpty && connected ? (
<Spin spinning size="small" />
) : (
<span style={{ color: token.colorTextTertiary }}>{emptyText}</span>
)
) : (
logs.map((log, index) => (
<div
key={`${index}-${log.message}`}
style={{ color: logColors[log.level] || token.colorText, lineHeight: '20px' }}
>
{log.message}
</div>
))
)}
<div ref={endRef} />
</div>
);
if (mode === 'card') {
return (
<Card
title={title}
size="small"
style={{ flex: 1, overflow: 'hidden', ...style }}
styles={{ body: { height: '100%', overflow: 'hidden', padding: 0 } }}
>
{logBody}
</Card>
);
}
return (
<div style={{ flexShrink: 0, borderTop: `1px solid ${token.colorBorderSecondary}`, ...style }}>
<div
style={{ display: 'flex', alignItems: 'center', cursor: collapsible ? 'pointer' : 'default', padding: '4px 0', userSelect: 'none' }}
onClick={() => collapsible && setVisible((value) => !value)}
>
<span style={{ fontWeight: 500, fontSize: 13 }}>{title}</span>
{collapsible && (
visible ? <UpOutlined style={{ marginLeft: 6, fontSize: 10 }} /> : <DownOutlined style={{ marginLeft: 6, fontSize: 10 }} />
)}
{logs.length > 0 && <span style={{ marginLeft: 8, fontSize: 12, color: token.colorTextTertiary }}>{logs.length} </span>}
{connected && <Tag color="processing" style={{ marginLeft: 8 }}></Tag>}
</div>
{visible && logBody}
</div>
);
}