ExecutionCheckModal.jsx 4.64 KB
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>
  )
}