> **本文回答**：图的创建 / 打开 / 更新 / 删除 / 版本 / 密码保护 / 隐藏 / 临时图。

## 一、创建（第一次打开某 mapid）

```js
const res = await svc.openMap({
  mapid: "my_new_map",             // 名字自定
  fileid: uploadRes.fileid,         // 必须：上传返回的 fileid
  mapopenway: vjmap.MapOpenWay.GeomRender,
  style: vjmap.openMapDarkStyle()
});
```

## 二、再次打开（已存在）

```js
const res = await svc.openMap({
  mapid: "my_new_map",
  mapopenway: vjmap.MapOpenWay.GeomRender,
  style: vjmap.openMapDarkStyle()
  // 不需要 fileid
});
```

## 三、更新（新版本）

保持 `mapid` 不变，加一个版本号（v1 → v2）：

```js
await svc.updateMap({
  mapid: "my_new_map",
  fileid: newUploadFileid,
  mapopenway: vjmap.MapOpenWay.GeomRender,
  style: { backcolor: 0 }
});
```

打开指定版本：

```js
await svc.openMap({
  mapid: "my_new_map",
  version: "v1",                   // 不指定用最新
  mapopenway: vjmap.MapOpenWay.GeomRender
});
```

## 四、删除

```js
// 只删 v1
await svc.cmdDeleteMap("my_new_map", "v1");

// 删除所有版本：version 必填，传 "*"
await svc.cmdDeleteMap("my_new_map", "*");

// 保留最近 N 个版本（mapid/version 在 URL 路径上，retainVersionMaxCount 在 body）
await svc.cmdDeleteMap("my_new_map", "*", 3);
// 等价于 svc.execCommand("deletemap", { retainVersionMaxCount: 3 }, "my_new_map", "*")
```

> **不可恢复**。

## 五、工作区

```js
svc.switchWorkspace("factoryA");
await svc.openMap({ mapid, mapopenway });

svc.switchWorkspace("");           // 默认工作区
```

相当于数据库 schema 隔离；各工作区可独立分配权限。

## 六、密码保护

### 创建时设置密码

```js
await svc.openMap({
  mapid, fileid,
  mapopenway: vjmap.MapOpenWay.GeomRender,
  secretKey: svc.pwdToSecretKey("pwd123")
});
```

### 打开有密码图

```js
const svc = new vjmap.Service(url, token);
// 方式 A：提前 addSecretKey，跳过弹窗
svc.addSecretKey("xxx");

// 方式 B：提前 addAccessKey（权限较小）
svc.addAccessKey("akxxxx");

// 方式 C：弹窗输入，走 cbInputPassword
await svc.openMap({
  mapid, mapopenway,
  cbInputPassword: async ({ mapid, tryPasswordCount }) => {
    if (tryPasswordCount > 3) return "";
    return prompt("请输入密码");
  }
});
```

### 取消密码

云端管理平台 → 该图操作菜单 → "设置密码" → 空。

SDK 方式：新密码传空串即取消保护（`key` 为旧 secretKey 或超级管理员 superKey）：

```js
await svc.cmdSetMapPassword(mapid, svc.pwdToSecretKey("旧密码"), "");
```

## 七、隐藏图

`mapid` 以 `ns_` 开头：对非 root 的 token 不可见（listMaps 不返回、管理平台不显示），仅通过 `token` + 直接输入 mapid 访问。

```js
await svc.openMap({ mapid: "ns_secretplan", ... });
```

## 八、临时图

`mapid` 以 `ns_temp_N_` 开头（N 分钟后自动删）：

```js
const id = vjmap.getTempMapId(30);      // 30 分钟过期
// => "ns_temp_30_xxxxx"

const res = await svc.updateMap({
  mapid: id,
  fileid,
  mapopenway: vjmap.MapOpenWay.Memory
});
```

场景：AI 生成的一次性图、PDF 导出前的变换图。

## 九、列出图形

```js
// REST：`GET/POST /map/cmd/listmaps/{mapid}/{version}`（SDK 封装为 svc.listMaps()）
const r = await svc.listMaps();
// 返回按 mapid 分组的对象：{ "sys_zp": [{ version:"v1", geom:true, uploadname:"xxx.dwg",
//   filename, db, maptype?, ismap3d?, errmsg?, lastModified }, ...], ... }
// 传 {curPage, pageCount} 分页时返回 {count, curPage, pageCount, mapIds, mapInfos, allMapIds}
```

## 十、常见坑

1. **updateMap 没传 fileid（或 fileid 与最新版本相同）** → 不报错、也不生成新版本，直接返回最新版本。
2. **同一个 mapid 跨 mapopenway 混用** → 第一次用什么模式就记住了；后续改模式得走云端管理台。
3. **cmdDeleteMap 在工作区错误** → 默认工作区可能没这个 mapid。先 `switchWorkspace`。
4. **`secretKey` 直接写在前端代码** → 泄漏风险。建议走 accessKey 或后端签名。
