# DDL解析接口 - 前端开发指南

## 接口概述

`/api/bd/ddlparse` 接口用于解析上传的文件，从中提取数据表结构定义信息。支持多种文件格式，适用于业务领域创建场景。

## 接口信息

| 属性 | 值 |
|------|-----|
| **URL** | `/api/bd/ddlparse` |
| **方法** | `POST` |
| **Content-Type** | `multipart/form-data` |
| **认证** | 根据系统配置 |

## 支持的文件类型

| 文件类型 | 扩展名 | 说明 |
|---------|--------|------|
| SQL文件 | `.sql` | DDL建表语句，支持多表 |
| Excel文件 | `.xlsx`, `.xls` | 表格形式的表结构定义 |
| Word文件 | `.docx` | 文档形式的表结构定义（暂不支持 `.doc` 格式） |
| PDF文件 | `.pdf` | PDF格式的表结构定义文档 |

## 请求参数

### Form Data

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `file` | File | 是 | 上传的文件，每次只能上传一个文件 |

## 响应格式

### 成功响应

```json
{
  "code": 200,
  "message": "操作成功",
  "data": [
    {
      "table_info": {
        "name_zh": "用户信息表",
        "name_en": "user_info"
      },
      "columns": [
        {
          "name_zh": "用户ID",
          "name_en": "user_id",
          "data_type": "INTEGER",
          "is_primary": "是",
          "comment": "用户唯一标识",
          "nullable": "否"
        },
        {
          "name_zh": "用户名",
          "name_en": "username",
          "data_type": "VARCHAR(50)",
          "is_primary": "否",
          "comment": "用户登录名",
          "nullable": "否"
        }
      ],
      "exist": false
    }
  ]
}
```

### 响应字段说明

#### 顶层结构

| 字段 | 类型 | 说明 |
|------|------|------|
| `code` | number | 状态码，200表示成功 |
| `message` | string | 操作结果消息 |
| `data` | array | 解析出的表结构数组，**始终为数组格式** |

#### 表结构对象 (data 数组元素)

| 字段 | 类型 | 说明 |
|------|------|------|
| `table_info` | object | 表的基本信息 |
| `table_info.name_zh` | string | 表的中文名称 |
| `table_info.name_en` | string | 表的英文名称 |
| `columns` | array | 字段列表 |
| `exist` | boolean | 该表在系统中是否已存在 |

#### 字段对象 (columns 数组元素)

| 字段 | 类型 | 说明 |
|------|------|------|
| `name_zh` | string | 字段中文名称 |
| `name_en` | string | 字段英文名称 |
| `data_type` | string | 数据类型（如 VARCHAR(50)、INTEGER） |
| `is_primary` | string | 是否主键："是" 或 "否" |
| `comment` | string | 字段注释/说明 |
| `nullable` | string | 是否可为空："是" 或 "否" |

### 错误响应

```json
{
  "code": 500,
  "message": "错误描述信息",
  "error": "详细错误信息（可选）"
}
```

#### 常见错误

| 错误消息 | 原因 |
|---------|------|
| `没有找到上传的文件，请上传一个文件` | 请求中没有包含文件 |
| `未选择文件` | 文件字段为空 |
| `不支持的文件类型: .xxx` | 上传了不支持的文件格式 |
| `暂不支持 .doc 格式，请转换为 .docx 格式后重新上传` | 上传了旧版 Word 格式 |
| `未找到有效的数据表定义信息` | 文件中没有识别到表结构 |

## 前端代码示例

### Vue 3 + Element Plus

```vue
<template>
  <el-upload
    ref="uploadRef"
    :auto-upload="false"
    :limit="1"
    :on-change="handleFileChange"
    :on-exceed="handleExceed"
    accept=".sql,.xlsx,.xls,.docx,.pdf"
  >
    <template #trigger>
      <el-button type="primary">选择文件</el-button>
    </template>
    <el-button 
      type="success" 
      @click="submitUpload"
      :loading="loading"
      style="margin-left: 10px"
    >
      解析文件
    </el-button>
    <template #tip>
      <div class="el-upload__tip">
        支持 .sql、.xlsx、.xls、.docx、.pdf 格式，单次仅支持上传一个文件
      </div>
    </template>
  </el-upload>

  <!-- 解析结果展示 -->
  <div v-if="tableList.length > 0" class="result-section">
    <h3>解析结果（共 {{ tableList.length }} 个表）</h3>
    <el-collapse v-model="activeNames">
      <el-collapse-item 
        v-for="(table, index) in tableList" 
        :key="index"
        :name="index"
      >
        <template #title>
          <span>
            {{ table.table_info.name_zh || table.table_info.name_en }}
            <el-tag v-if="table.exist" type="warning" size="small">已存在</el-tag>
          </span>
        </template>
        <el-table :data="table.columns" stripe>
          <el-table-column prop="name_zh" label="字段中文名" />
          <el-table-column prop="name_en" label="字段英文名" />
          <el-table-column prop="data_type" label="数据类型" />
          <el-table-column prop="is_primary" label="主键" width="80" />
          <el-table-column prop="nullable" label="可空" width="80" />
          <el-table-column prop="comment" label="备注" />
        </el-table>
      </el-collapse-item>
    </el-collapse>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'

const uploadRef = ref()
const loading = ref(false)
const currentFile = ref(null)
const tableList = ref([])
const activeNames = ref([0])

const handleFileChange = (file) => {
  currentFile.value = file.raw
}

const handleExceed = () => {
  ElMessage.warning('每次只能上传一个文件')
}

const submitUpload = async () => {
  if (!currentFile.value) {
    ElMessage.warning('请先选择文件')
    return
  }

  const formData = new FormData()
  formData.append('file', currentFile.value)

  loading.value = true
  try {
    const response = await axios.post('/api/bd/ddlparse', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    })

    if (response.data.code === 200) {
      tableList.value = response.data.data
      ElMessage.success(`解析成功，共识别到 ${tableList.value.length} 个表`)
    } else {
      ElMessage.error(response.data.message || '解析失败')
    }
  } catch (error) {
    ElMessage.error('请求失败：' + (error.message || '未知错误'))
  } finally {
    loading.value = false
  }
}
</script>

<style scoped>
.result-section {
  margin-top: 20px;
}
</style>
```

### React + Ant Design

```tsx
import React, { useState } from 'react';
import { Upload, Button, message, Collapse, Table, Tag, Space } from 'antd';
import { UploadOutlined, FileSearchOutlined } from '@ant-design/icons';
import type { UploadFile } from 'antd/es/upload/interface';
import axios from 'axios';

interface Column {
  name_zh: string;
  name_en: string;
  data_type: string;
  is_primary: string;
  comment: string;
  nullable: string;
}

interface TableInfo {
  table_info: {
    name_zh: string;
    name_en: string;
  };
  columns: Column[];
  exist: boolean;
}

const DDLParseUpload: React.FC = () => {
  const [fileList, setFileList] = useState<UploadFile[]>([]);
  const [loading, setLoading] = useState(false);
  const [tableList, setTableList] = useState<TableInfo[]>([]);

  const handleUpload = async () => {
    if (fileList.length === 0) {
      message.warning('请先选择文件');
      return;
    }

    const formData = new FormData();
    formData.append('file', fileList[0] as any);

    setLoading(true);
    try {
      const response = await axios.post('/api/bd/ddlparse', formData, {
        headers: { 'Content-Type': 'multipart/form-data' }
      });

      if (response.data.code === 200) {
        setTableList(response.data.data);
        message.success(`解析成功，共识别到 ${response.data.data.length} 个表`);
      } else {
        message.error(response.data.message || '解析失败');
      }
    } catch (error: any) {
      message.error('请求失败：' + (error.message || '未知错误'));
    } finally {
      setLoading(false);
    }
  };

  const columns = [
    { title: '字段中文名', dataIndex: 'name_zh', key: 'name_zh' },
    { title: '字段英文名', dataIndex: 'name_en', key: 'name_en' },
    { title: '数据类型', dataIndex: 'data_type', key: 'data_type' },
    { title: '主键', dataIndex: 'is_primary', key: 'is_primary', width: 80 },
    { title: '可空', dataIndex: 'nullable', key: 'nullable', width: 80 },
    { title: '备注', dataIndex: 'comment', key: 'comment' },
  ];

  return (
    <div>
      <Space>
        <Upload
          fileList={fileList}
          beforeUpload={(file) => {
            setFileList([file]);
            return false;
          }}
          onRemove={() => setFileList([])}
          accept=".sql,.xlsx,.xls,.docx,.pdf"
          maxCount={1}
        >
          <Button icon={<UploadOutlined />}>选择文件</Button>
        </Upload>
        <Button
          type="primary"
          onClick={handleUpload}
          loading={loading}
          icon={<FileSearchOutlined />}
        >
          解析文件
        </Button>
      </Space>
      <p style={{ color: '#999', fontSize: 12, marginTop: 8 }}>
        支持 .sql、.xlsx、.xls、.docx、.pdf 格式
      </p>

      {tableList.length > 0 && (
        <div style={{ marginTop: 20 }}>
          <h3>解析结果（共 {tableList.length} 个表）</h3>
          <Collapse
            items={tableList.map((table, index) => ({
              key: index,
              label: (
                <span>
                  {table.table_info.name_zh || table.table_info.name_en}
                  {table.exist && <Tag color="warning" style={{ marginLeft: 8 }}>已存在</Tag>}
                </span>
              ),
              children: (
                <Table
                  dataSource={table.columns}
                  columns={columns}
                  rowKey="name_en"
                  size="small"
                  pagination={false}
                />
              ),
            }))}
            defaultActiveKey={[0]}
          />
        </div>
      )}
    </div>
  );
};

export default DDLParseUpload;
```

### 原生 JavaScript (Fetch API)

```javascript
async function parseDDLFile(file) {
  const formData = new FormData();
  formData.append('file', file);

  try {
    const response = await fetch('/api/bd/ddlparse', {
      method: 'POST',
      body: formData
    });

    const result = await response.json();

    if (result.code === 200) {
      console.log('解析成功，表数量:', result.data.length);
      return result.data;
    } else {
      throw new Error(result.message);
    }
  } catch (error) {
    console.error('解析失败:', error);
    throw error;
  }
}

// 使用示例
document.getElementById('fileInput').addEventListener('change', async (e) => {
  const file = e.target.files[0];
  if (!file) return;

  try {
    const tables = await parseDDLFile(file);
    // 处理解析结果
    tables.forEach(table => {
      console.log('表名:', table.table_info.name_zh);
      console.log('字段数:', table.columns.length);
      console.log('是否已存在:', table.exist);
    });
  } catch (error) {
    alert('解析失败: ' + error.message);
  }
});
```

## 文件格式建议

### SQL 文件

标准的 DDL 建表语句，支持多表：

```sql
CREATE TABLE user_info (
    user_id INT PRIMARY KEY COMMENT '用户ID',
    username VARCHAR(50) NOT NULL COMMENT '用户名',
    email VARCHAR(100) COMMENT '邮箱地址'
);

CREATE TABLE order_info (
    order_id BIGINT PRIMARY KEY COMMENT '订单ID',
    user_id INT NOT NULL COMMENT '用户ID',
    total_amount DECIMAL(10,2) COMMENT '订单金额'
);
```

### Excel 文件

建议使用表格形式，包含以下列：

| 字段英文名 | 字段中文名 | 数据类型 | 是否主键 | 是否可空 | 备注 |
|-----------|-----------|---------|---------|---------|------|
| user_id | 用户ID | INTEGER | 是 | 否 | 用户唯一标识 |
| username | 用户名 | VARCHAR(50) | 否 | 否 | 登录名 |

### Word 文件

文档中包含表格形式的字段定义，系统会自动识别文档中的表格并解析。

### PDF 文件

PDF 中包含的表结构定义文本或表格，系统会提取文本和表格内容进行解析。

## 注意事项

1. **文件大小限制**：建议单个文件不超过 10MB
2. **编码格式**：SQL 文件建议使用 UTF-8 编码
3. **单次上传**：每次请求只能上传一个文件
4. **解析时间**：由于使用 LLM 进行智能解析，复杂文档可能需要几秒钟
5. **exist 字段**：表示该表名是否在系统的业务领域中已存在，用于提示用户避免重复创建
6. **Word 格式**：仅支持 `.docx` 格式，旧版 `.doc` 格式需要转换后上传

## 更新日志

| 版本 | 日期 | 更新内容 |
|------|------|---------|
| v1.1.0 | 2025-12-26 | 新增 Excel、Word、PDF 文件支持 |
| v1.0.0 | - | 初始版本，仅支持 SQL 文件 |

