# 云存储

云存储是团队级的文件空间，用于存放需要在 MoreLogin 自动化流程中反复使用的文件。你可以只上传一次，用标签归类，之后再检索，并删除不再需要的文件。

它与云手机的文件传输接口是两回事。云手机文件接口把文件搬进或搬出某一台具体设备；云存储接口管理的是共享文件库，即文件被设备、计划任务、RPA 模板或其他自动化逻辑使用之前的那一层。

## 你可以做什么

| 能力 | 用途 | 相关接口 |
|  --- | --- | --- |
| 存储概览 | 在上传或清理文件之前，查看总容量、已用容量、到期时间与容量状态。 | 查询云存储信息 |
| 文件检索 | 分页列出云存储文件，并按文件名、文件类型、标签或文件 ID 过滤。 | 分页查询云存储文件 |
| 文件上传 | 申请预签名上传地址，把文件内容上传到对象存储，然后在 MoreLogin 确认完成。 | 批量申请预签名上传地址、确认上传完成 |
| 文件清理 | 从共享存储库中删除一个或多个文件。 | 批量删除云存储文件 |
| 文件打标 | 覆盖或追加文件标签，按项目、客户、用途或流程归类文件。 | 设置文件标签、追加文件标签、查询文件标签 |
| 标签管理 | 创建、编辑、列出与删除可复用的文件标签。 | 查询全部标签、创建标签、编辑标签、删除标签 |


## 常见场景

- APK、媒体文件、文档或测试素材只上传一次，在自动化里反复使用。
- 按客户、活动、应用版本、环境或流程把文件归类整理。
- 在你的内部工具里做一个文件选择器：调用文件分页接口，配合文件名与标签过滤。
- 流程结束后批量清理过期或不再使用的文件。
- 通过创建标签并挂到已上传文件上，把外部素材系统与 MoreLogin 打通。


## 接口接入方式

| 方式 | Base URL | 路径前缀 | 适用场景 |
|  --- | --- | --- | --- |
| **Open API** | `https://api.morelogin.com` | `/cloudstorage` | 服务端对服务端调用、远程工具、CI/CD、后端服务 |
| **Local API** | `http://127.0.0.1:40000` | `/api/cloudstorage` | 与 MoreLogin 客户端运行在同一台机器上的脚本或桌面工具 |


鉴权细节见[鉴权](/zh/api-reference/getting-started/authentication)。

## 上传流程

云存储上传采用预签名地址流程。你的代码不会把二进制文件直接传给 MoreLogin 接口。

1. 调用**批量申请预签名上传地址**，传入文件名列表（含扩展名）。
2. 对返回的每一项，用 HTTPS `PUT` 把二进制文件上传到 `presignedUrl`。
3. 用返回的文件 `id` 调用**确认上传完成**。
4. 用**分页查询云存储文件**或**查询文件标签**核对并展示已上传的文件。


```bash
# 1. Request a presigned upload URL
curl -X POST "https://api.morelogin.com/cloudstorage/upload/init" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fileNames": ["example.jpg"]
  }'

# 2. Upload file content to the returned presignedUrl
curl -X PUT "PRESIGNED_URL_FROM_RESPONSE" \
  -H "Content-Type: image/jpeg" \
  --data-binary "@example.jpg"

# 3. Confirm upload completion (id from step 1 response)
curl -X POST "https://api.morelogin.com/cloudstorage/upload/complete" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 1800000000000001
  }'
```

Local API 请保持相同的请求体，把路径换成 `http://127.0.0.1:40000/api/cloudstorage/...`。

## 在云手机 RPA 中使用云存储文件

文件上传并确认之后，云手机 RPA 模板参数就可以用云存储文件 ID 引用它。请使用 MoreLogin 云文件协议，而不是外部公开下载地址：

```text
morelogin://cloudfile?ids=1,2
```

`ids` 是用逗号分隔的云存储文件 ID 列表。只能用英文逗号，且不带空格。文件 ID 可以从上传完成的响应中获得，也可以从**分页查询云存储文件**获得。

单个文件：

```text
morelogin://cloudfile?ids=1800000000001001
```

多个文件：

```text
morelogin://cloudfile?ids=1800000000001001,1800000000001002
```

当 RPA 参数是媒体或文件类型时，请保留必需的 `__Extra__` 元数据，并把参数值设为云文件协议 URI：

```json
{
  "__Extra__": {
    "videoDownloadUrl": { "name": "video.mp4", "size": 204800000 }
  },
  "videoDownloadUrl": "morelogin://cloudfile?ids=1,2"
}
```

这适用于云手机 RPA 的计划任务、市场模板、个人模板，以及任何期望传入可复用上传文件的 RPA 节点参数。RPA 运行时会从 MoreLogin 云存储解析该文件，因此文件不需要暴露成公开的 HTTPS 地址。

## 完整示例：用云存储中的视频运行云手机 RPA

本示例把 `video.mp4` 上传到云存储、挂上一个标签，然后创建一个一次性云手机 RPA 任务，在 `videoDownloadUrl` 模板参数中使用该文件。

示例使用 Local API 路径。若用 Open API，请保持请求体不变，只替换：

- `http://127.0.0.1:40000/api/cloudstorage/...` 换成 `https://api.morelogin.com/cloudstorage/...`
- `http://127.0.0.1:40000/api/cloudphone/...` 换成 `https://api.morelogin.com/cloudphone/...`


### 1. 为 RPA 素材创建标签

```bash
curl -X POST "http://127.0.0.1:40000/api/cloudstorage/tag/create" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tagName": "RPA Assets"
  }'
```

保存返回的标签 `id`，例如 `1800000000000101`。

### 2. 申请预签名上传地址

```bash
curl -X POST "http://127.0.0.1:40000/api/cloudstorage/upload/init" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fileNames": ["video.mp4"]
  }'
```

保存返回的文件 `id` 与 `presignedUrl`。

### 3. 上传文件二进制内容

把文件内容上传到 `presignedUrl`。这个请求发往上一步返回的对象存储地址，而不是 MoreLogin 接口。

```bash
curl -X PUT "PRESIGNED_URL_FROM_RESPONSE" \
  -H "Content-Type: video/mp4" \
  --data-binary "@video.mp4"
```

### 4. 确认上传完成

```bash
curl -X POST "http://127.0.0.1:40000/api/cloudstorage/upload/complete" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 1800000000000001
  }'
```

保存返回的云存储文件 ID，例如 `1800000000001001`。

### 4.1 给文件挂标签

```bash
curl -X POST "http://127.0.0.1:40000/api/cloudstorage/file/tag/add" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fileId": 1800000000001001,
    "tagIds": [1800000000000101]
  }'
```

如果你的上传完成响应没有直接返回文件 ID，就分页查询文件：

```bash
curl -X POST "http://127.0.0.1:40000/api/cloudstorage/file/page" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pageNo": 1,
    "pageSize": 20,
    "fileName": "video",
    "tagIds": [1800000000000101]
  }'
```

### 5. 构造 RPA 模板参数

在 MoreLogin 云文件协议里使用云存储文件 ID：

```text
morelogin://cloudfile?ids=1800000000001001
```

对于名为 `videoDownloadUrl` 的 RPA 模板参数，按下面的形式构造 JSON 对象：

```json
{
  "__Extra__": {
    "videoDownloadUrl": {
      "name": "video.mp4",
      "size": 204800000
    }
  },
  "videoDownloadUrl": "morelogin://cloudfile?ids=1800000000001001"
}
```

然后把它转义成 JSON 字符串作为 `templateParameter`：

```json
"{\"__Extra__\":{\"videoDownloadUrl\":{\"name\":\"video.mp4\",\"size\":204800000}},\"videoDownloadUrl\":\"morelogin://cloudfile?ids=1800000000001001\"}"
```

### 6. 创建一次性云手机 RPA 任务

创建任务之前，从云手机列表接口取 `cloudPhoneId`，从市场模板或个人模板列表接口取 `templateId`。

```bash
curl -X POST "http://127.0.0.1:40000/api/cloudphone/rpa/onceTask/save" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cloudPhoneId": 1678331966138097,
    "scheduleName": "Upload video from Cloud Storage",
    "templateId": 1678347487160256,
    "templateParameter": "{\"__Extra__\":{\"videoDownloadUrl\":{\"name\":\"video.mp4\",\"size\":204800000}},\"videoDownloadUrl\":\"morelogin://cloudfile?ids=1800000000001001\"}",
    "description": "Use a Cloud Storage video file in a one-time Cloud Phone RPA task"
  }'
```

### 7. 校验任务

查询云手机 RPA 任务列表或子任务列表，确认执行状态：

```bash
curl -X POST "http://127.0.0.1:40000/api/cloudphone/rpa/task/page" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pageNo": 1,
    "pageSize": 20,
    "taskName": "Upload video from Cloud Storage"
  }'
```

关键点在于 RPA 任务接收到的 `videoDownloadUrl` 形如 `morelogin://cloudfile?ids=...`。MoreLogin 在运行时从云存储解析该文件，因此你的集成不需要把文件托管在公开地址上。

## 标签工作流

标签是云存储文件的可复用元数据。一个文件可以有多个标签。

- 用**创建云存储文件标签**创建诸如 `Invoices`、`APK`、`Customer A` 或 `RPA Assets` 这样的标签。
- 想覆盖文件上的全部标签时，用**设置文件标签**。
- 想在不移除既有标签的前提下追加，用**追加文件标签**。
- 用**查询全部云存储文件标签**在你的界面里构建标签过滤器。
- 用**查询文件标签**展示选中文件上挂了哪些标签。


示例：给文件追加一个标签，同时不移除它已有的标签。

```bash
curl -X POST "https://api.morelogin.com/cloudstorage/file/tag/add" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fileId": 1800000000001001,
    "tagIds": [1800000000000103]
  }'
```

## 接口对照表

| 任务 | Open API 路径 | Local API 路径 |
|  --- | --- | --- |
| 查询存储信息 | `GET /cloudstorage/info` | `GET /api/cloudstorage/info` |
| 分页查询文件 | `POST /cloudstorage/file/page` | `POST /api/cloudstorage/file/page` |
| 申请预签名上传地址 | `POST /cloudstorage/upload/init` | `POST /api/cloudstorage/upload/init` |
| 确认上传完成 | `POST /cloudstorage/upload/complete` | `POST /api/cloudstorage/upload/complete` |
| 批量删除文件 | `POST /cloudstorage/file/delete/batch` | `POST /api/cloudstorage/file/delete/batch` |
| 设置文件标签 | `POST /cloudstorage/file/tag/set` | `POST /api/cloudstorage/file/tag/set` |
| 追加文件标签 | `POST /cloudstorage/file/tag/add` | `POST /api/cloudstorage/file/tag/add` |
| 查询文件上的标签 | `POST /cloudstorage/file/tag/query` | `POST /api/cloudstorage/file/tag/query` |
| 查询全部标签 | `GET /cloudstorage/tag/all` | `GET /api/cloudstorage/tag/all` |
| 创建标签 | `POST /cloudstorage/tag/create` | `POST /api/cloudstorage/tag/create` |
| 编辑标签 | `POST /cloudstorage/tag/edit` | `POST /api/cloudstorage/tag/edit` |
| 删除标签 | `POST /cloudstorage/tag/delete/batch` | `POST /api/cloudstorage/tag/delete/batch` |


## 接口文档

| 接口 | 说明 |
|  --- | --- |
| [Cloud Storage Open API](/zh/api-reference/cloud-storage/open-api) | 通过 `https://api.morelogin.com` 远程访问，OAuth2 鉴权 |
| [Cloud Storage Local API](/zh/api-reference/cloud-storage/local-api) | 通过 `http://127.0.0.1:40000` 本地访问 |


> **注意**：Local API 路径带 `/api/` 前缀，Open API 路径不带。