ExecutionCheckModal.jsx
4.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import React from 'react'
import { Modal, Table, Tag, Button, Space, Alert } from 'antd'
import {
CheckCircleOutlined,
WarningOutlined,
CloseCircleOutlined,
InfoCircleOutlined,
ThunderboltOutlined,
} from '@ant-design/icons'
const levelMap = {
high: { color: 'red', icon: <CloseCircleOutlined />, label: '高风险' },
medium: { color: 'orange', icon: <WarningOutlined />, label: '中风险' },
warn: { color: 'gold', icon: <WarningOutlined />, label: '警告' },
info: { color: 'blue', icon: <InfoCircleOutlined />, label: '提示' },
ok: { color: 'green', icon: <CheckCircleOutlined />, label: '正常' },
}
export default function ExecutionCheckModal({ open, onClose, onConfirm, checkResult, sql }) {
if (!checkResult) return null
const { syntaxOk, syntaxError, warnings, risks, estimatedRows, sqlType, explainRows } = checkResult
// 判断是否可以继续执行
const hasHighRisk = risks.some(r => r.level === 'high')
const canExecute = syntaxOk && !syntaxError
const explainColumns = [
{ title: '表', dataIndex: 'table', key: 'table', ellipsis: true, width: 120 },
{ title: '类型', dataIndex: 'type', key: 'type', width: 80 },
{ title: '索引', dataIndex: 'key', key: 'key', ellipsis: true, width: 120 },
{ title: '预估行数', dataIndex: 'rows', key: 'rows', width: 90 },
{ title: '额外信息', dataIndex: 'Extra', key: 'Extra', ellipsis: true },
]
return (
<Modal
title="SQL预执行检查"
open={open}
onCancel={onClose}
width={760}
className="check-modal"
footer={
<Space>
<Button onClick={onClose}>取消</Button>
{canExecute && (
<Button
type="primary"
danger={hasHighRisk}
onClick={onConfirm}
icon={<ThunderboltOutlined />}
>
{hasHighRisk ? '确认执行(存在高风险)' : '确认执行'}
</Button>
)}
</Space>
}
>
{/* 语法检查 */}
<div style={{ marginBottom: 16 }}>
<h4 style={{ marginBottom: 8 }}>语法检查</h4>
{syntaxOk ? (
<div className="check-item ok">
<CheckCircleOutlined style={{ marginRight: 8 }} />
SQL语法检查通过
{sqlType !== 'SELECT' && (
<Tag color="orange" style={{ marginLeft: 8 }}>{sqlType}语句</Tag>
)}
</div>
) : (
<div className="check-item high">
<CloseCircleOutlined style={{ marginRight: 8 }} />
SQL语法错误:{syntaxError}
</div>
)}
</div>
{/* 风险提示 */}
{risks.length > 0 && (
<div style={{ marginBottom: 16 }}>
<h4 style={{ marginBottom: 8 }}>风险提示</h4>
{risks.map((risk, i) => (
<div key={i} className={`check-item ${risk.level}`}>
{levelMap[risk.level]?.icon}
<span style={{ marginLeft: 8 }}>{risk.message}</span>
</div>
))}
</div>
)}
{/* 警告 */}
{warnings.length > 0 && (
<div style={{ marginBottom: 16 }}>
<h4 style={{ marginBottom: 8 }}>性能警告</h4>
{warnings.map((w, i) => (
<div key={i} className={`check-item ${w.level}`}>
{levelMap[w.level]?.icon}
<span style={{ marginLeft: 8 }}>{w.message}</span>
</div>
))}
</div>
)}
{/* 预估行数 */}
<div style={{ marginBottom: 16 }}>
<h4 style={{ marginBottom: 8 }}>预估扫描行数</h4>
<Tag color={estimatedRows > 100000 ? 'red' : estimatedRows > 10000 ? 'orange' : 'green'} style={{ fontSize: 14, padding: '4px 12px' }}>
{estimatedRows.toLocaleString()} 行
</Tag>
</div>
{/* EXPLAIN结果 */}
{explainRows && explainRows.length > 0 && (
<div className="explain-table">
<h4 style={{ marginBottom: 8 }}>执行计划</h4>
<Table
dataSource={explainRows}
columns={explainColumns}
rowKey={(_, i) => i}
size="small"
pagination={false}
scroll={{ x: 600 }}
bordered
/>
</div>
)}
{/* 待执行的SQL */}
<div style={{ marginTop: 16 }}>
<h4 style={{ marginBottom: 8 }}>待执行的SQL</h4>
<pre style={{
background: '#f5f5f5',
padding: 12,
borderRadius: 6,
fontSize: 12,
maxHeight: 200,
overflow: 'auto',
whiteSpace: 'pre-wrap',
wordBreak: 'break-all',
}}>
{sql}
</pre>
</div>
</Modal>
)
}