# 文件管理

## GET /api/fkteams/files

获取工作区目录下的文件和文件夹列表。

**请求参数** (Query)：

| 参数   | 类型   | 必填 | 说明                                     |
| ------ | ------ | ---- | ---------------------------------------- |
| `path` | string | 否   | 相对于工作区根目录的子路径，空则为根目录 |

**成功响应** (200)：

```json
{
  "code": 0,
  "message": "success",
  "data": [
    {
      "name": "file.txt",
      "path": "subdir/file.txt",
      "is_dir": false,
      "size": 1234,
      "mod_time": 1700000000
    }
  ]
}
```

| 字段       | 说明                    |
| ---------- | ----------------------- |
| `name`     | 文件/目录名             |
| `path`     | 相对路径                |
| `is_dir`   | 是否为目录              |
| `size`     | 文件大小（字节）        |
| `mod_time` | 修改时间（Unix 时间戳） |

排序规则：文件夹在前 → 同类型按修改时间倒序 → 时间相同按名称升序。隐藏文件（`.` 开头）被过滤。

**失败响应**：

| 状态码 | message                      | 说明           |
| ------ | ---------------------------- | -------------- |
| 400    | 无效的路径                   | 路径包含 `..`  |
| 404    | 目录不存在或无法访问         | 路径不可达     |
| 400    | 路径不是目录                 | 目标不是目录   |
| 500    | 读取目录失败                 | IO 错误        |

---

## GET /api/fkteams/files/search

递归搜索文件名（不区分大小写）。

**请求参数** (Query)：

| 参数 | 类型   | 必填 | 说明       |
| ---- | ------ | ---- | ---------- |
| `q`  | string | 是   | 搜索关键词 |

**成功响应** (200)：

```json
{
  "code": 0,
  "message": "success",
  "data": [
    {
      "name": "report.pdf",
      "path": "docs/report.pdf",
      "is_dir": false,
      "size": 51200,
      "mod_time": 1700000000
    }
  ]
}
```

最多返回 100 条结果，搜索深度最大 10 层。排序规则：文件夹在前，同类型按名称排序。隐藏文件被过滤。

**失败响应**：

| 状态码 | message                      | 说明           |
| ------ | ---------------------------- | -------------- |
| 400    | 搜索关键词不能为空           | 未提供关键词   |

---

## GET /api/fkteams/files/download

下载工作区中的指定文件。

**请求参数** (Query)：

| 参数   | 类型   | 必填 | 说明                   |
| ------ | ------ | ---- | ---------------------- |
| `path` | string | 是   | 文件相对于工作区的路径 |

**成功响应** (200)：

文件内容以 `Content-Disposition: attachment` 方式返回。

**失败响应**：

| 状态码 | message                      | 说明           |
| ------ | ---------------------------- | -------------- |
| 400    | 缺少 path 参数               | 未提供路径     |
| 400    | 无效的路径                   | 路径遍历       |
| 400    | 不支持下载目录               | 目标是目录     |
| 404    | 文件不存在                   | 路径不可达     |

---

## POST /api/fkteams/files/download/batch

批量下载文件，将多个文件/文件夹打包为 ZIP 返回。

**请求 Body**：

```json
{
  "paths": ["docs/report.pdf", "images/"]
}
```

| 字段    | 类型     | 必填 | 说明                     |
| ------- | -------- | ---- | ------------------------ |
| `paths` | string[] | 是   | 文件或目录的相对路径数组 |

**成功响应** (200)：

ZIP 文件以 `Content-Disposition: attachment; filename="download.zip"` 方式返回。目录会递归打包，隐藏文件被过滤。

**失败响应**：

| 状态码 | message                      | 说明           |
| ------ | ---------------------------- | -------------- |
| 400    | 缺少 paths 参数              | 路径数组为空   |
| 400    | 无效的路径                   | 路径遍历       |
| 404    | 文件不存在: \<path\>         | 路径不可达     |

---

## POST /api/fkteams/files/upload

上传文件到工作区（支持多文件）。

**请求格式**：`multipart/form-data`

| 字段   | 类型   | 必填 | 说明                                   |
| ------ | ------ | ---- | -------------------------------------- |
| `file` | file   | 是   | 上传的文件（可多个同名字段实现多文件） |
| `path` | string | 否   | 目标子目录路径，空则为根目录           |

**成功响应** (200)：

```json
{
  "code": 0,
  "message": "success",
  "data": [
    {
      "name": "file.txt",
      "path": "subdir/file.txt",
      "is_dir": false,
      "size": 1234,
      "mod_time": 1700000000
    }
  ]
}
```

返回所有成功上传文件的 `FileInfo` 数组。

**失败响应**：

| 状态码 | message                      | 说明           |
| ------ | ---------------------------- | -------------- |
| 400    | 无效的路径                   | 路径遍历       |
| 400    | 解析表单失败                 | 表单格式错误   |
| 400    | 未找到上传文件               | 无文件字段     |
| 400    | 没有文件上传成功             | 全部文件失败   |
| 500    | 创建目录失败                 | IO 错误        |

---

## POST /api/fkteams/files/upload/chunk

大文件分片上传。每个分片单独请求，所有分片到齐后自动合并。

**请求格式**：`multipart/form-data`

| 字段          | 类型   | 必填 | 说明                   |
| ------------- | ------ | ---- | ---------------------- |
| `file`        | file   | 是   | 分片内容               |
| `uploadId`    | string | 是   | 上传标识（客户端生成） |
| `chunkIndex`  | int    | 是   | 分片序号（0-based）    |
| `totalChunks` | int    | 是   | 总分片数               |
| `fileName`    | string | 是   | 最终文件名             |
| `path`        | string | 否   | 目标子目录路径         |

**进行中响应** (200)：

```json
{
  "code": 0,
  "message": "success",
  "data": {
    "uploadId": "abc123",
    "chunkIndex": 0,
    "received": 1,
    "total": 3,
    "completed": false
  }
}
```

**完成响应** (200)（最后一个分片到达时）：

```json
{
  "code": 0,
  "message": "success",
  "data": {
    "uploadId": "abc123",
    "completed": true,
    "file": {
      "name": "large.zip",
      "path": "subdir/large.zip",
      "is_dir": false,
      "size": 104857600,
      "mod_time": 1700000000
    }
  }
}
```

**失败响应**：

| 状态码 | message                      | 说明             |
| ------ | ---------------------------- | ---------------- |
| 400    | 缺少必要参数                 | 参数不完整       |
| 400    | 无效的分片序号               | chunkIndex 非法  |
| 400    | 无效的总分片数               | totalChunks 非法 |
| 400    | 分片序号超出范围             | 超出总片数       |
| 400    | 无效的文件名                 | 文件名不安全     |
| 400    | 无效的路径                   | 路径遍历         |

---

## DELETE /api/fkteams/files

删除工作区中的文件或目录。

**请求 Body**：

```json
{
  "path": "subdir/file.txt",
  "force": false
}
```

| 字段    | 类型   | 必填 | 说明                                      |
| ------- | ------ | ---- | ----------------------------------------- |
| `path`  | string | 是   | 文件或目录的相对路径                      |
| `force` | bool   | 否   | 删除非空目录时须设为 `true`，默认 `false` |

**成功响应** (200)：

```json
{
  "code": 0,
  "message": "success",
  "data": null
}
```

**失败响应**：

| 状态码 | message                              | 说明           |
| ------ | ------------------------------------ | -------------- |
| 400    | 缺少 path 参数                       | 未提供路径     |
| 400    | 无效的路径                           | 路径遍历       |
| 400    | 无效的文件路径                       | 尝试删除根目录 |
| 400    | 目录非空，请设置 force:true 确认删除 | 非空目录未确认 |
| 404    | 文件或目录不存在                     | 路径不可达     |

---

## GET /api/fkteams/files/serve/*filepath

以 inline 方式返回工作区中的文件，适用于需要浏览器直接渲染的场景（如 HTML 预览、图片展示等）。支持浏览器自然解析相对引用资源。

**路径参数**：

| 参数       | 类型   | 说明                         |
| ---------- | ------ | ---------------------------- |
| `filepath` | string | 相对于工作区根目录的文件路径 |

**成功响应** (200)：

文件内容以 `Content-Disposition: inline` 方式返回（即浏览器直接展示而非下载）。若目标为目录，会尝试返回该目录下的 `index.html`。

**失败响应**：

| 状态码 | message            | 说明         |
| ------ | ------------------ | ------------ |
| 400    | 缺少文件路径         | 路径参数为空   |
| 400    | 无效的路径             | 路径遍历       |
| 400    | 不支持目录             | 目标是目录且无 index.html |
| 404    | 文件不存在             | 路径不可达     |
