# 材质管理系统 API 文档

## 基础信息

  - **Base URL**: `http://10.99.98.248:8081/api/v1`
- **认证方式**: API Token
- **Content-Type**: `application/json`

## 认证

所有API请求需要在Header中携带Token：

```
X-API-Token: seatons3d
```

错误响应示例：
```json
{
  "code": 401,
  "message": "missing API token"
}
```

---

## 通用响应格式

### 成功响应
```json
{
  "code": 0,
  "message": "success",
  "data": { ... }
}
```

### 分页响应
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "items": [...],
    "total": 303,
    "page": 1,
    "page_size": 20
  }
}
```

### 错误响应
```json
{
  "code": 400,
  "message": "error description"
}
```

### 错误码
| 状态码 | 说明 |
|--------|------|
| 200 | 成功 |
| 201 | 创建成功 |
| 400 | 请求参数错误 |
| 401 | 未授权（Token无效） |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |

---

## 材质管理接口

### 1. 获取材质列表

**GET** `/materials`

#### 请求参数（Query）
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| page | int | 否 | 页码，默认1 |
| page_size | int | 否 | 每页数量，默认20，最大100 |
| name | string | 否 | 按名称模糊搜索 |

#### 请求示例
```bash
curl -H "X-API-Token: seatons3d" \
  "http://10.99.98.248:8081/api/v1/materials?page=1&page_size=10&name=red"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "items": [
      {
        "id": 4,
        "name": "dgnColor4",
        "diffuse_r": 255,
        "diffuse_g": 0,
        "diffuse_b": 0,
        "alpha": 255,
        "shininess": 20,
        "specular_r": 230,
        "specular_g": 230,
        "specular_b": 230,
        "ambient_r": 50,
        "ambient_g": 50,
        "ambient_b": 50,
        "metallic": 0,
        "roughness": 0,
        "reflectance": 0,
        "created_at": "2025-12-09T09:53:33.209555Z",
        "updated_at": "2025-12-09T09:53:33.209555Z"
      }
    ],
    "total": 303,
    "page": 1,
    "page_size": 10
  }
}
```

---

### 2. 添加材质

**POST** `/materials`

#### 请求Body
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| name | string | 是 | 材质名称 |
| diffuse_r | float | 否 | 漫反射-红 (0-255) |
| diffuse_g | float | 否 | 漫反射-绿 (0-255) |
| diffuse_b | float | 否 | 漫反射-蓝 (0-255) |
| alpha | float | 否 | 透明度 (0-255) |
| shininess | float | 否 | 光泽度 |
| specular_r | float | 否 | 高光-红 (0-255) |
| specular_g | float | 否 | 高光-绿 (0-255) |
| specular_b | float | 否 | 高光-蓝 (0-255) |
| ambient_r | float | 否 | 环境光-红 (0-255) |
| ambient_g | float | 否 | 环境光-绿 (0-255) |
| ambient_b | float | 否 | 环境光-蓝 (0-255) |
| metallic | float | 否 | 金属度 |
| roughness | float | 否 | 粗糙度 |
| reflectance | float | 否 | 反射率 |

#### 请求示例
```bash
curl -X POST -H "X-API-Token: seatons3d" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "红色金属",
    "diffuse_r": 255,
    "diffuse_g": 50,
    "diffuse_b": 50,
    "alpha": 255,
    "metallic": 0.8,
    "roughness": 0.2
  }' \
  "http://10.99.98.248:8081/api/v1/materials"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "created",
  "data": {
    "id": 305,
    "name": "红色金属",
    "diffuse_r": 255,
    "diffuse_g": 50,
    "diffuse_b": 50,
    "alpha": 255,
    "shininess": 0,
    "specular_r": 0,
    "specular_g": 0,
    "specular_b": 0,
    "ambient_r": 0,
    "ambient_g": 0,
    "ambient_b": 0,
    "metallic": 0.8,
    "roughness": 0.2,
    "reflectance": 0.5,
    "created_at": "2025-12-09T18:02:22.846141Z",
    "updated_at": "2025-12-09T18:02:22.846141Z"
  }
}
```

---

### 3. 获取材质详情

**GET** `/materials/:id`

#### 路径参数
| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 材质ID |

#### 请求示例
```bash
curl -H "X-API-Token: seatons3d" \
  "http://10.99.98.248:8081/api/v1/materials/4"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "id": 4,
    "name": "dgnColor4",
    "diffuse_r": 255,
    "diffuse_g": 0,
    "diffuse_b": 0,
    "alpha": 255,
    "shininess": 20,
    "specular_r": 230,
    "specular_g": 230,
    "specular_b": 230,
    "ambient_r": 50,
    "ambient_g": 50,
    "ambient_b": 50,
    "metallic": 0,
    "roughness": 0,
    "reflectance": 0,
    "created_at": "2025-12-09T09:53:33.209555Z",
    "updated_at": "2025-12-09T09:53:33.209555Z"
  }
}
```

#### 错误响应
```json
{
  "code": 404,
  "message": "material not found"
}
```

---

### 4. 编辑材质

**PUT** `/materials/:id`

#### 路径参数
| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 材质ID |

#### 请求Body
同"添加材质"接口

#### 请求示例
```bash
curl -X PUT -H "X-API-Token: seatons3d" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "红色金属-更新版",
    "diffuse_r": 200,
    "diffuse_g": 100,
    "diffuse_b": 50,
    "alpha": 255,
    "metallic": 0.9,
    "roughness": 0.1
  }' \
  "http://10.99.98.248:8081/api/v1/materials/305"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "id": 305,
    "name": "红色金属-更新版",
    "diffuse_r": 200,
    "diffuse_g": 100,
    "diffuse_b": 50,
    "alpha": 255,
    ...
  }
}
```

---

### 5. 删除材质

**DELETE** `/materials/:id`

#### 路径参数
| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 材质ID |

#### 请求示例
```bash
curl -X DELETE -H "X-API-Token: seatons3d" \
  "http://10.99.98.248:8081/api/v1/materials/305"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "id": 305
  }
}
```

> **注意**: 删除材质会级联删除所有相关的绑定关系

---

## 绑定管理接口

### 6. 绑定材质到多个Group

**POST** `/materials/:id/bindings`

将一个材质绑定到多个叶子节点（group_id），支持幂等操作（重复绑定不会报错）。

#### 路径参数
| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 材质ID |

#### 请求Body
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| group_ids | string[] | 是 | 叶子节点ID数组 |

#### 请求示例
```bash
curl -X POST -H "X-API-Token: seatons3d" \
  -H "Content-Type: application/json" \
  -d '{
    "group_ids": ["node_001", "node_002", "node_003"]
  }' \
  "http://10.99.98.248:8081/api/v1/materials/4/bindings"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "material_id": 4,
    "group_ids": ["node_001", "node_002", "node_003"]
  }
}
```

---

### 7. 解绑材质与Group

**DELETE** `/materials/:id/bindings`

#### 路径参数
| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 材质ID |

#### 请求Body
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| group_ids | string[] | 是 | 要解绑的叶子节点ID数组 |

#### 请求示例
```bash
curl -X DELETE -H "X-API-Token: seatons3d" \
  -H "Content-Type: application/json" \
  -d '{
    "group_ids": ["node_001", "node_002"]
  }' \
  "http://10.99.98.248:8081/api/v1/materials/4/bindings"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "material_id": 4,
    "unbound": ["node_001", "node_002"]
  }
}
```

---

### 8. 获取材质关联的所有Group（分页）

**GET** `/materials/:id/groups`

#### 路径参数
| 参数 | 类型 | 说明 |
|------|------|------|
| id | int | 材质ID |

#### 请求参数（Query）
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| page | int | 否 | 页码，默认1 |
| page_size | int | 否 | 每页数量，默认20，最大100 |

#### 请求示例
```bash
curl -H "X-API-Token: seatons3d" \
  "http://10.99.98.248:8081/api/v1/materials/4/groups?page=1&page_size=10"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": {
    "items": [
      "20251021105717834754",
      "20251021105717834758",
      "20251021105717834762"
    ],
    "total": 22,
    "page": 1,
    "page_size": 10
  }
}
```

---

### 9. 根据Group IDs批量查询关联材质

**POST** `/groups/materials`

根据一个或多个叶子节点ID，查询它们关联的材质详情。

#### 请求Body
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| group_ids | string[] | 是 | 叶子节点ID数组 |

#### 请求示例
```bash
curl -X POST -H "X-API-Token: seatons3d" \
  -H "Content-Type: application/json" \
  -d '{
    "group_ids": ["202510211057245681447", "aDsIXMkjxdm2CDUj9gTvf"]
  }' \
  "http://10.99.98.248:8081/api/v1/groups/materials"
```

#### 响应示例
```json
{
  "code": 0,
  "message": "success",
  "data": [
    {
      "group_id": "202510211057245681447",
      "material": {
        "id": 4,
        "name": "dgnColor4",
        "diffuse_r": 255,
        "diffuse_g": 0,
        "diffuse_b": 0,
        "alpha": 255,
        "shininess": 20,
        "specular_r": 230,
        "specular_g": 230,
        "specular_b": 230,
        "ambient_r": 50,
        "ambient_g": 50,
        "ambient_b": 50,
        "metallic": 0,
        "roughness": 0,
        "reflectance": 0,
        "created_at": "2025-12-09T09:53:33.209555Z",
        "updated_at": "2025-12-09T09:53:33.209555Z"
      }
    },
    {
      "group_id": "aDsIXMkjxdm2CDUj9gTvf",
      "material": {
        "id": -1,
        "name": "默认值",
        "diffuse_r": 192,
        "diffuse_g": 192,
        "diffuse_b": 192,
        ...
      }
    }
  ]
}
```

> **注意**: 如果某个group_id没有绑定材质，则不会出现在返回结果中

---

## 健康检查

**GET** `/health`

此接口无需认证。

#### 请求示例
```bash
curl http://10.99.98.248:8081/health
```

#### 响应示例
```json
{
  "status": "ok"
}
```

---

## 数据模型

### Material（材质）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | int64 | 材质ID（主键） |
| name | string | 材质名称 |
| diffuse_r | float64 | 漫反射-红 (0-255) |
| diffuse_g | float64 | 漫反射-绿 (0-255) |
| diffuse_b | float64 | 漫反射-蓝 (0-255) |
| alpha | float64 | 透明度 (0-255) |
| shininess | float64 | 光泽度 |
| specular_r | float64 | 高光-红 (0-255) |
| specular_g | float64 | 高光-绿 (0-255) |
| specular_b | float64 | 高光-蓝 (0-255) |
| ambient_r | float64 | 环境光-红 (0-255) |
| ambient_g | float64 | 环境光-绿 (0-255) |
| ambient_b | float64 | 环境光-蓝 (0-255) |
| metallic | float64 | 金属度 |
| roughness | float64 | 粗糙度 |
| reflectance | float64 | 反射率 |
| created_at | timestamp | 创建时间 |
| updated_at | timestamp | 更新时间 |

### MaterialBinding（材质绑定）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | int64 | 绑定ID（主键） |
| material_id | int64 | 材质ID（外键） |
| group_id | string | 叶子节点ID |
| created_at | timestamp | 创建时间 |
