# WebCAD

> 分类代号：C.6  本章共 **6 个接口**

---

## 没有"启用开关"可探

- 下面 6 个 cmd 在图形服务里**始终注册**，不存在服务端 feature flag
- `GET /api/v1/service/webcad` **不是**启用探针，而是 WebCAD 前端的 license 握手：要求 query 带前端加密的 `stamp`，解不开就回 HTTP 403 `{code:7, msg:"error parameter!"}`；成功时回 `{status, version, time, stamp}`，从不返回 `enabled` 字段。二次开发不要调它（旧版 SDK 的 `webcadEnabled()` / `webcad_enabled()` 据此恒判"未启用"，已移除）
- webcad 数据类接口只对"经 `convertWebcad` 转过"或有 vcad 数据的 mapid 有意义；`listWebcadDraws` 总能返回 `{imports, designs}` 列表

---

## 快速索引

| 序号 | SDK 方法 | URL |
|----:|---------|-----|
| 42 | `list_webcad_draws` / `listWebcadDraws` | `GET /api/v1/map/cmd/listWebcadDraws/_/v1` |
| 43 | `get_webcad_data` / `getWebcadData` | `POST /api/v1/map/cmd/getWebcadData/{mapid}/{version}` |
| 44 | `save_webcad_patch` / `saveWebcadPatch` | `POST /api/v1/map/cmd/saveWebcadPatch/{mapid}/{version}` |
| 45 | `delete_webcad_draw` / `deleteWebcadDraw` | `POST /api/v1/map/cmd/deleteWebcadDraw/{mapid}/{version}` |
| 46 | `convert_webcad` / `convertWebcad` | `POST /api/v1/map/cmd/convertWebCAD/{mapid}/{version}` |
| 47 | `export_webcad` / `exportWebcad` | `POST /api/v1/map/cmd/exportWebCAD/_null/v1` |

> 后端实际还有 3 个分支管理命令（`createWebcadBranch` / `deleteWebcadBranch` / `mergeWebcadBranch`，同走 `cmd/...` 路由），SDK 未封装，需要时可裸 POST 调用。

---

## 42 · 列出 WebCAD 图 `listWebcadDraws`

**URL**：`GET /api/v1/map/cmd/listWebcadDraws/_/v1`  
**可选参数**（query）：`mapid` / `version`（过滤 imports 列表）、`designPath`（过滤 designs 列表）。后端不读 `type`（那是 `getWebcadData` 的参数）。

**响应**——返回 `imports` 与 `designs` 两个数组：

```json
{
  "status": true,
  "imports": [ ... ],
  "designs": [ ... ]
}
```

### Python / Node

```python
svc.list_webcad_draws()
```

```javascript
await svc.listWebcadDraws();
```

---

## 43 · 读取 WebCAD 数据 `getWebcadData`

**URL**：`POST /api/v1/map/cmd/getWebcadData/{mapid}/{version}`

### 请求参数

| 字段 | 说明 |
|------|------|
| `type` | 库类型，默认 `imports` |
| `designPath` | WebCAD 设计路径 |
| `patchId` | **必填**：要取的版本——`base`（基底）或 `pN`（第 N 个补丁） |
| `branch` | 分支名，默认 `main` |
| `editAreas` / `editLayers` | 可选：按编辑区域/图层过滤返回实体（JSON） |
| `selByCrossing` | 配合 editAreas 的相交模式（默认 true） |
| `clipbounds` | 可选：裁剪范围 |

### 响应

成功返回 **vcad 数据本体**——但形态是 **gzip 压缩的原始字节，SDK 不解压也不解析**：Python `get_webcad_data` 返回 `bytes`（`\x1f\x8b` 魔数开头，签名却声明 `Dict`），须自行 `gzip.decompress` 后得到 JSON（含 `dbBlocks` 实体树）。

缺 `patchId` 时走错误通道：**HTTP 500** + `{"error":"patchId is required"}`，SDK 抛 `VjmapError(status=500)`（错误体在 `e.body`）。

> ⚠️ **普通图也能取到 `base`**：未经 convertWebcad 的普通 mapid 调 `patchId="base"` 并不报 500，照样返回 gzip 字节（基底就是整图 vcad 数据）。HTTP 500 对应缺 patchId / 取不存在的 `pN` 补丁等非法路径。

### Python

```python
import gzip, json
raw = svc.get_webcad_data("proj_wc", "v1", patchId="base", branch="main")
data = json.loads(gzip.decompress(raw))  # raw 是 gzip bytes，不是 dict
```

---

## 44 · 保存 WebCAD 补丁 `saveWebcadPatch`

**URL**：`POST /api/v1/map/cmd/saveWebcadPatch/{mapid}/{version}`

### 请求参数

| 字段 | 说明 |
|------|------|
| `patch` | **必填**：补丁内容（JSON 字符串） |
| `patchCompressed` | patch 为 gzip+base64 压缩格式（默认 false） |
| `parentId` | 基于哪个补丁提交，用于冲突检测：`base` 或 `pN`（默认 `base`） |
| `branch` | 分支名（默认 `main`） |
| `author` / `userId` / `userName` | 提交者标识（可选） |
| `remark` | 提交说明（**不是 `comment`**） |
| `designPath` | WebCAD 设计路径 |
| `type` | 库类型，默认 `imports` |
| `drawingName` | 图纸名（可选） |
| `editAreas` / `editLayers` | 编辑区域/图层（JSON） |
| `tileAlpha` | 瓦片透明度 |
| `conflictResolution` / `conflictResolutionCompressed` | 冲突解决指令（JSON/压缩） |

### 响应

```json
{ "status": true, "patchId": "p13", "branch": "main" }
```

冲突时返回 `{ "status": false, "error": "conflict", "conflict": {...} }`。

### Python

```python
svc.save_webcad_patch(
    "proj_wc", "v1",
    patch='[{"op":"add","entity":{...}}]',
    branch="main",
    author="alice",
    remark="add hatch",
    parentId="p12",
)
```

---

## 45 · 删除 WebCAD 图 `deleteWebcadDraw`

**URL**：`POST /api/v1/map/cmd/deleteWebcadDraw/{mapid}/{version}`

### 请求参数

| 字段 | 说明 |
|------|------|
| `type` | 库类型，默认 `imports` |
| `designPath` | WebCAD 设计路径 |
| `branch` | 分支名（默认 `main`） |
| `patchId` | 可选：只删指定补丁；不给则删除该图整个 imports（或 designPath 对应 design）的 vcad 数据 |

参数全不给时 SDK 走 GET（空 JSON body 的 POST 会被 cmd 路由回 500 `param error`）。

### 响应

```json
{ "status": true }
```

---

## 46 · 转为 WebCAD `convertWebCAD`

把一张已上传的 DWG 转成 WebCAD 可用的结构（初始化分支、预计算可编辑实体）。

**URL**：`POST /api/v1/map/cmd/convertWebCAD/{mapid}/{version}`

### 请求参数（均可选）

> 全不传时注意：cmd 路由对**空 JSON body 的 POST** 回 HTTP 500 `param error`（cmd 路由通用行为，与本命令无关）。SDK 的 `convertWebcad` / `deleteWebcadDraw` 在无参数时改走 GET 规避；手写 REST 用 GET 或至少带一个字段。

| 字段 | 说明 |
|------|------|
| `path` | 源 DWG 文件路径（缺省用当前图档） |
| `polylineSimplifyEnabled` | 多段线简化开关（默认 true） |
| `polylineSimplifyMinPoints` / `polylineSimplifyMinPoints1` | 简化点数阈值（默认 30 / 5） |
| `polylineSimplifyEpsilon` | 简化容差（默认 0.05；小于阈值用 1e-8） |
| `gzip` | 返回数据 gzip（默认 true） |

### 响应

```json
{ "status": true, "path": ".../data/mapdraws/imports/<mapid>/<version>/" }
```

转换后的 vcad 数据落在 `path` 目录（前端 SDK 自动接管）。

> 对普通非 webcad 图：`save_webcad_patch` 对普通图也返回 `{status:true, patchId:"p1", branch:"main"}`——**不校验图是否为 webcad 结构**；`delete_webcad_draw` 对不存在的 drawingName 也返回 `{status:true}`（静默成功）；`convert_webcad` 对普通图正常返回 `{status:true, path}`。早先记录的"convert_webcad 对普通图 HTTP 500"其实是**空 JSON body 的 POST** 被 cmd 路由拒（`param error`），不是转换失败。

---

## 47 · 导出 WebCAD 为 DWG `exportWebCAD`

**URL**：`POST /api/v1/map/cmd/exportWebCAD/_null/v1`

### 请求参数

| 字段 | 说明 |
|------|------|
| `mapid` / `version` | 要导出的 WebCAD 图 |
| `type` | 库类型，默认 `imports` |
| `designPath` | WebCAD 设计路径 |
| `branch` | 导出哪个分支（默认 `main`） |
| `vcadData` | 或直接传 base64 vcad 数据（不给 mapid 时） |
| `filename` | 输出文件名（可省，自动生成） |
| `isTileMode` | 瓦片模式导出（默认 false） |
| `editAreas` / `editLayers` | 只导出指定区域/图层（JSON） |
| `unGroup` | 解组（默认 false） |
| `exportDimAsNative` | 标注导出为原生 DIM（默认 false） |
| `useCache` | 结果缓存（默认 true） |
| `isZoomExtents` / `screenWidth` / `screenHeight` | 视图相关（可选） |

### 响应

```json
{ "status": true, "path": "...", "filename": "xxx.dwg", "cached": true }
```

> ⚠️ 错误形态：mapid 不存在时**不抛 HTTP 异常**，返回 body 级 `{"error": "Failed to read base.vcad", "status": false}`——与 `updateMetadata` 的 HTTP 404 抛错、`renameMap` 的 body 级 `error:true` 构成三种不同错误形态，调用后务必判 `status`。
