# 文件上传记录功能说明

## 概述

现在系统已经支持将用户的文件上传记录持久化到数据库中。每次文件上传成功后，系统会自动记录以下信息：

## 记录的信息

- **user_id**: 用户ID
- **user_name**: 用户名
- **token_hash**: 使用的Token Hash（用于追踪哪个token上传的文件）
- **file_id**: 文件唯一标识符
- **file_name**: 文件名
- **file_size**: 文件大小（字节）
- **file_md5**: 文件MD5值（如果提供）
- **file_path**: 文件在服务器上的存储路径
- **dataset_id**: 数据集ID
- **total_chunks**: 分片总数
- **upload_status**: 上传状态（默认为"completed"）
- **upload_started_at**: 上传开始时间
- **upload_completed_at**: 上传完成时间
- **created_at**: 记录创建时间

## 数据库表结构

表名：`file_upload_records`

```sql
CREATE TABLE file_upload_records (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id VARCHAR(64) NOT NULL,
    user_name VARCHAR(128) NOT NULL,
    token_hash VARCHAR(64) NOT NULL,
    file_id VARCHAR(128) UNIQUE NOT NULL,
    file_name VARCHAR(512) NOT NULL,
    file_size BIGINT NOT NULL,
    file_md5 VARCHAR(32),
    file_path VARCHAR(1024) NOT NULL,
    dataset_id VARCHAR(128) NOT NULL,
    total_chunks INT NOT NULL,
    upload_status VARCHAR(16) NOT NULL DEFAULT 'completed',
    upload_started_at DATETIME,
    upload_completed_at DATETIME NOT NULL,
    created_at DATETIME NOT NULL,
    INDEX idx_user_id (user_id),
    INDEX idx_token_hash (token_hash),
    INDEX idx_file_id (file_id),
    INDEX idx_dataset_id (dataset_id),
    INDEX idx_created_at (created_at)
);
```

## 初始化数据库

系统会在初始化时自动创建 `file_upload_records` 表。运行以下命令初始化数据库：

```bash
python init_db.py
```

或者在应用启动时会自动调用 `create_tables()` 函数创建所有表。

## 使用说明

### 自动记录

文件上传记录会在文件合并成功后自动保存到数据库，无需额外操作。系统会在 `/api/upload/merge` 接口中自动处理。

### API接口

#### 1. 查询上传记录

**接口地址**: `GET /api/upload/records`

**请求参数**:
- `page` (可选): 页码，默认1
- `page_size` (可选): 每页大小，默认10，最大100
- `user_id` (可选): 按用户ID筛选（仅管理员可使用，普通用户自动查询自己的记录）
- `dataset_id` (可选): 按数据集ID筛选
- `file_name` (可选): 按文件名模糊搜索

**请求头**:
```
Authorization: Bearer <your_token>
```

**响应示例**:
```json
{
  "code": 200,
  "message": "查询成功，共 25 条记录",
  "total": 25,
  "page": 1,
  "page_size": 10,
  "records": [
    {
      "id": 1,
      "user_id": "user_123",
      "user_name": "张三",
      "file_id": "abc123",
      "file_name": "example.pdf",
      "file_size": 10485760,
      "file_md5": "d41d8cd98f00b204e9800998ecf8427e",
      "file_path": "/uploads/dataset_001/example.pdf",
      "dataset_id": "dataset_001",
      "total_chunks": 10,
      "upload_status": "completed",
      "upload_started_at": "2024-01-01T10:00:00",
      "upload_completed_at": "2024-01-01T10:05:00",
      "created_at": "2024-01-01T10:05:00"
    }
  ]
}
```

#### 2. 获取上传统计信息

**接口地址**: `GET /api/upload/records/stats`

**请求头**:
```
Authorization: Bearer <your_token>
```

**响应示例**:
```json
{
  "code": 200,
  "message": "统计信息获取成功",
  "data": {
    "total_files": 125,
    "total_size": 5368709120,
    "total_size_gb": 5.0,
    "today_files": 10,
    "today_size": 419430400,
    "today_size_gb": 0.39
  }
}
```

### 前端调用示例

#### JavaScript/TypeScript

```javascript
// 查询上传记录（分页）
async function getUploadRecords(page = 1, pageSize = 10) {
  const response = await fetch(
    `http://your-server.com/api/upload/records?page=${page}&page_size=${pageSize}`,
    {
      headers: {
        'Authorization': `Bearer ${your_token}`
      }
    }
  );
  const data = await response.json();
  return data;
}

// 按数据集查询
async function getRecordsByDataset(datasetId) {
  const response = await fetch(
    `http://your-server.com/api/upload/records?dataset_id=${datasetId}`,
    {
      headers: {
        'Authorization': `Bearer ${your_token}`
      }
    }
  );
  const data = await response.json();
  return data;
}

// 搜索文件名
async function searchByFileName(fileName) {
  const response = await fetch(
    `http://your-server.com/api/upload/records?file_name=${encodeURIComponent(fileName)}`,
    {
      headers: {
        'Authorization': `Bearer ${your_token}`
      }
    }
  );
  const data = await response.json();
  return data;
}

// 获取统计信息
async function getUploadStats() {
  const response = await fetch(
    'http://your-server.com/api/upload/records/stats',
    {
      headers: {
        'Authorization': `Bearer ${your_token}`
      }
    }
  );
  const data = await response.json();
  return data;
}
```

#### Python

```python
import requests

# 查询上传记录
def get_upload_records(token, page=1, page_size=10):
    url = f"http://your-server.com/api/upload/records"
    headers = {"Authorization": f"Bearer {token}"}
    params = {"page": page, "page_size": page_size}
    response = requests.get(url, headers=headers, params=params)
    return response.json()

# 按数据集查询
def get_records_by_dataset(token, dataset_id):
    url = f"http://your-server.com/api/upload/records"
    headers = {"Authorization": f"Bearer {token}"}
    params = {"dataset_id": dataset_id}
    response = requests.get(url, headers=headers, params=params)
    return response.json()

# 获取统计信息
def get_upload_stats(token):
    url = "http://your-server.com/api/upload/records/stats"
    headers = {"Authorization": f"Bearer {token}"}
    response = requests.get(url, headers=headers)
    return response.json()
```

### 查询上传记录

您可以通过SQL查询来获取上传记录：

```python
from database import get_db, FileUploadRecord

# 获取某个用户的所有上传记录
db = get_db()
records = db.query(FileUploadRecord).filter(
    FileUploadRecord.user_id == "user_123"
).all()

# 获取某个数据集的所有上传记录
records = db.query(FileUploadRecord).filter(
    FileUploadRecord.dataset_id == "dataset_456"
).order_by(FileUploadRecord.created_at.desc()).all()

# 转换为字典
for record in records:
    print(record.to_dict())
```

### 查询示例

```python
# 查询最近上传的10个文件
recent_uploads = db.query(FileUploadRecord)\
    .order_by(FileUploadRecord.created_at.desc())\
    .limit(10)\
    .all()

# 查询某个用户今天上传的文件
from datetime import datetime, timedelta
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
today_uploads = db.query(FileUploadRecord).filter(
    FileUploadRecord.user_id == "user_123",
    FileUploadRecord.created_at >= today
).all()

# 统计用户上传的总文件大小
from sqlalchemy import func
total_size = db.query(func.sum(FileUploadRecord.file_size)).filter(
    FileUploadRecord.user_id == "user_123"
).scalar()
```

## 注意事项

1. **性能**: 记录保存是在文件合并完成后进行的，如果数据库连接失败，不会影响文件上传流程
2. **唯一性**: `file_id` 是唯一的，同一个 `file_id` 只能记录一次
3. **时区**: 所有时间字段使用 UTC 时间
4. **存储**: 建议定期清理旧的上传记录或进行归档，以避免表过大

## 权限说明

- **普通用户**: 只能查询自己的上传记录和统计信息
- **管理员**: 可以通过 `user_id` 参数查询任何用户的上传记录

## 性能建议

1. **分页查询**: 建议使用分页，避免一次性加载大量数据
2. **索引优化**: 数据库已对常用查询字段建立索引（user_id, dataset_id, file_id, created_at）
3. **缓存**: 对于统计信息，建议前端进行适当缓存

## 后续扩展

可以基于这个功能实现：
- ✅ 用户上传历史查询接口（已实现）
- ✅ 上传统计报表（已实现）
- 文件使用分析
- 存储空间管理
- 审计日志
- 下载记录追踪

