> **本文回答**：`svc.openMap` 的完整用法、必要/可选参数、四种 `fileid` 形态、错误处理。

## 一、签名

```js
const svc = new vjmap.Service(serviceUrl, accessToken);
const res = await svc.openMap({
  mapid: string,                   // 必填：上传时给图取的唯一 ID
  fileid: string,                  // 第一次打开某 mapid 时必填；之后不传（d.ts 仅 string）
  filedoc: string,                 // 或改用 filedoc 传 JSON 文档（程序化新建，与 fileid 二选一）
  mapopenway: vjmap.MapOpenWay,    // 可选：Memory / GeomRender（缺省 GeomRender）
  style: object                    // 可选：服务端渲染样式（openMapDarkStyle / openMapLightStyle 等）
});
if (res.error) throw new Error(res.error);
// 成功时 res 至少包含：{ bounds, version, ... }
```

## 二、fileid 的四种形态

| 形态 | 示例 | 说明 |
|---|---|---|
| (1) 服务器本地路径 | `"mapfiles/ccf12a1f8711.dwg"` | 相对 vjmap 服务端 `data/` 目录的路径 |
| (2) HTTP 网络路径 | `"https://host/path/foo.dwg"` | 后端会先下载再打开 |
| (3) 上传后得到的 fileid | `"5f8a9e..."` | 通过 [backend/upload-create-map](../backend/upload-create-map.md) 上传得到 |
| (4) JSON 定义图（程序化新建） | `filedoc: doc.toDoc()` | ⚠️ JSON 文档走 **`filedoc`** 字段（非 fileid），通过前端数据直接造图，参见 [backend/upload-create-map](../backend/upload-create-map.md) |

**只在"第一次用此 mapid 打开"时必须传 fileid；一旦打开过，后端会缓存该 mapid 的映射关系，以后可以只传 mapid。**

## 三、style 参数

- `vjmap.openMapDarkStyle()`：深色底图预置（最常用；容器背景建议 `#022B4F` 或同色系）。
- `vjmap.openMapLightStyle()`：浅色底图预置。
- 也可以传 `IMapStyleParam` 对象自定义：`{ backcolor: 0xFFFFFF, layeron: "...", layeroff: "...", lineweight: [...], expression: "..." }`（字段全集见 d.ts `IMapStyleParam`，无 `layerColor` 字段）。

不传 style 时后端用默认；前端如果要换风格，除了 style 还需要指定 map 的 `style: svc.rasterStyle() / svc.vectorStyle()`（看 [map-open-way](map-open-way.md)）。

## 四、最小可运行示例

```js
const svc = new vjmap.Service(
  "https://vjmap.com/server/api/v1",
  "你的Token"
);

const res = await svc.openMap({
  mapid: "sys_zp",                               // 服务端已有的示例图 ID
  mapopenway: vjmap.MapOpenWay.GeomRender,       // 几何数据渲染
  style: vjmap.openMapDarkStyle()
});
if (res.error) throw new Error(res.error);

const prj = new vjmap.GeoProjection(res.bounds); // res.bounds 是字符串
const map = new vjmap.Map({
  container: "map",
  style: svc.vectorStyle(),                      // 与 mapopenway 对应
  center: prj.toLngLat(prj.getMapExtent().center()),
  zoom: 2,
  renderWorldCopies: false
});
map.attach(svc, prj);
await map.onLoad();
```

## 五、res 的常见字段

| 字段 | 用途 |
|---|---|
| `res.error` | 带内（HTTP 200）错误字符串，如密码图缺密码；成功时不存在。HTTP 非 2xx 的失败（403/404/500）是 Promise reject，不在这里 |
| `res.bounds` | 图的几何范围（字符串格式 `"[x1,y1,x2,y2]"`），用于建 `GeoProjection` |
| `res.version` | 当前版本号（切换历史版本会用到） |
| `res.darkMode` | 当前图是否深色模式 |

## 六、错误处理模板

```js
let res;
try {
  res = await svc.openMap({ mapid, mapopenway: vjmap.MapOpenWay.GeomRender });
} catch (e) {
  // HTTP 非 2xx 直接 reject，e = {status, response, data, xhr}（不是 Error）：
  //   403 + {code:7, msg:"Token is invalid" / "Token expired"} → Token 缺失/无效/过期（网关层）
  //   404 + {error:"map file is not exist"}                   → mapid 不存在且没传 fileid
  //   400 + {error:"local file xxx is not exist"}             → fileid 指向的本地文件不存在
  //   0                                                       → 网络 / CORS
  console.error("openMap 失败:", e.status, e.response);
  return;
}
if (res.error) {
  // 带内错误（HTTP 200），如密码图："no permission to access this map, ..."
  console.error("openMap 失败:", res.error);
  return;
}
```

## 七、常见坑

1. **没传 fileid 就打开不存在的 mapid** → HTTP 404 `{error:"map file is not exist"}`（Promise reject）。修法：第一次传 fileid，或先通过 upload-map 流程。
2. **同一张图不同 mapopenway 混用** → 内存打开后以后改几何渲染需在管理台显式转换（见 [map-open-way](map-open-way.md)）。
3. **前端传的 `style` 和 Map 的 `style` 不匹配** → 栅格瓦片配矢量样式时地图白屏。
