ConnectionModal.jsx 5.23 KB
import React, { useState, useEffect } from 'react'
import { Modal, Form, Input, Select, Button, message, Space, List, Tag, Popconfirm } from 'antd'
import { PlusOutlined, DeleteOutlined, LinkOutlined, DisconnectOutlined } from '@ant-design/icons'
import request from '../utils/request'

export default function ConnectionModal({ open, onClose, onConnect, activeConnId }) {
  const [form] = Form.useForm()
  const [connections, setConnections] = useState([])
  const [loading, setLoading] = useState(false)
  const [testLoading, setTestLoading] = useState(false)
  const [showForm, setShowForm] = useState(false)

  useEffect(() => {
    if (open) loadConnections()
  }, [open])

  const loadConnections = async () => {
    const res = await request.get('/connection')
    if (res.success) setConnections(res.data)
  }

  const handleTest = async () => {
    try {
      const values = await form.validateFields()
      setTestLoading(true)
      const res = await request.post('/connection/test', values)
      if (res.success) {
        message.success('连接测试成功')
      } else {
        message.error(`连接测试失败: ${res.message}`)
      }
    } catch {
      // 表单验证失败
    } finally {
      setTestLoading(false)
    }
  }

  const handleSave = async () => {
    try {
      const values = await form.validateFields()
      setLoading(true)
      const res = await request.post('/connection', values)
      if (res.success) {
        message.success('连接保存成功')
        form.resetFields()
        setShowForm(false)
        loadConnections()
      } else {
        message.error(res.message)
      }
    } catch {
      // 表单验证失败
    } finally {
      setLoading(false)
    }
  }

  const handleDelete = async (id) => {
    await request.delete(`/connection/${id}`)
    message.success('已删除')
    loadConnections()
  }

  const handleConnect = (conn) => {
    onConnect(conn)
    onClose()
  }

  return (
    <Modal
      title="数据库连接管理"
      open={open}
      onCancel={onClose}
      footer={null}
      width={640}
    >
      <div style={{ marginBottom: 16 }}>
        <Button
          type="primary"
          icon={<PlusOutlined />}
          onClick={() => setShowForm(!showForm)}
        >
          {showForm ? '收起表单' : '新增连接'}
        </Button>
      </div>

      {showForm && (
        <Form form={form} layout="vertical" style={{ marginBottom: 24, padding: 16, background: '#fafafa', borderRadius: 8 }}>
          <Form.Item name="name" label="连接名称" rules={[{ required: true, message: '请输入连接名称' }]}>
            <Input placeholder="例如:生产环境" />
          </Form.Item>
          <div style={{ display: 'flex', gap: 12 }}>
            <Form.Item name="host" label="主机地址" rules={[{ required: true }]} style={{ flex: 2 }}>
              <Input placeholder="192.168.1.100" />
            </Form.Item>
            <Form.Item name="port" label="端口" initialValue="3306" style={{ flex: 1 }}>
              <Input placeholder="3306" />
            </Form.Item>
          </div>
          <div style={{ display: 'flex', gap: 12 }}>
            <Form.Item name="user" label="用户名" rules={[{ required: true }]} style={{ flex: 1 }}>
              <Input placeholder="root" />
            </Form.Item>
            <Form.Item name="password" label="密码" style={{ flex: 1 }}>
              <Input.Password placeholder="密码" />
            </Form.Item>
          </div>
          <Form.Item name="database" label="数据库名" rules={[{ required: true }]}>
            <Input placeholder="saas_project_v2" />
          </Form.Item>
          <Form.Item>
            <Space>
              <Button onClick={handleTest} loading={testLoading} icon={<LinkOutlined />}>
                测试连接
              </Button>
              <Button type="primary" onClick={handleSave} loading={loading}>
                保存连接
              </Button>
            </Space>
          </Form.Item>
        </Form>
      )}

      <List
        dataSource={connections}
        locale={{ emptyText: '暂无连接配置,请点击上方按钮新增' }}
        renderItem={item => (
          <List.Item
            actions={[
              <Button
                type="link"
                size="small"
                icon={<LinkOutlined />}
                onClick={() => handleConnect(item)}
                disabled={activeConnId === item.id}
              >
                {activeConnId === item.id ? '已连接' : '连接'}
              </Button>,
              <Popconfirm title="确定删除该连接?" onConfirm={() => handleDelete(item.id)}>
                <Button type="link" size="small" danger icon={<DeleteOutlined />}>
                  删除
                </Button>
              </Popconfirm>,
            ]}
          >
            <List.Item.Meta
              title={
                <span>
                  {item.name}
                  {activeConnId === item.id && (
                    <Tag color="green" style={{ marginLeft: 8 }}>当前连接</Tag>
                  )}
                </span>
              }
              description={`${item.host}:${item.port} / ${item.database} (${item.user})`}
            />
          </List.Item>
        )}
      />
    </Modal>
  )
}