# 符号与分类管理

> 示例：
> - `vjcad/example/insert/symbol/05managecategory.js` — 分类 CRUD
> - `vjcad/example/insert/symbol/06managesymbol.js` — 符号查询 / 详情 / 删除

本地与服务端各有一套独立的 API，**接口形态接近但不相通**。两者一般不会自动同步。

## 1. 分类管理

### 本地（IndexedDB）

```js
const localService = getLocalStorageService();

const cats = await localService.getLocalSymbolCategories();          // 列表
const cat  = await localService.createLocalSymbolCategory(name);      // 新建
await localService.updateLocalSymbolCategory(cat.id, newName);        // 重命名
await localService.deleteLocalSymbolCategory(cat.id);                 // 删除（级联删除该分类下所有符号）
```

### 服务端

```js
let service;
try {
    service = Engine.service;          // 未配置 serviceUrl 时 getter 直接抛错，不会返回空
} catch (e) {
    throw new Error("服务不可用：未配置 serviceUrl");
}

const cats = await service.getSymbolCategories();                  // 列表
const cat  = await service.createSymbolCategory(name);              // 新建（需要权限）
await service.updateSymbolCategory(cat.id, newName);                // 重命名
await service.deleteSymbolCategory(cat.id);                         // 删除（仅 root；服务端连同分类目录下所有符号一起删）
```

> 完整代码：`vjcad/example/insert/symbol/05managecategory.js`

## 2. 符号查询

### 本地

```js
const symbols = await localService.getLocalSymbolList(categoryId);     // 元数据列表
const detail  = await localService.getLocalSymbol(symbol.id);          // { record, vcadData }（vcadData 已解压），不存在为 null
const stats   = await localService.getLocalSymbolStats();              // {categoryCount, symbolCount, totalSize}
```

### 服务端（支持分页 / 关键字）

```js
const result = await service.getSymbolList(categoryId, {
    page: 1,
    pageSize: 10,
    keyword: ""
});
// result: { list, total, page, pageSize }

const fullSymbol = await service.getSymbol(symbolId);                  // 含压缩 data
const vcadData   = await decompressSymbolData(fullSymbol.data);        // 解压
```

> 完整代码：`vjcad/example/insert/symbol/06managesymbol.js`

## 3. 删除

```js
// 本地
await localService.deleteLocalSymbol(symbolId);

// 服务端
await service.deleteSymbol(symbolId);
```

> 删除符号属于 **不可逆操作**，示例代码里通常注释掉以避免误操作。

## 4. 数据流总览

```mermaid
flowchart TB
    subgraph 本地
        L1[getLocalSymbolCategories] --> L2[getLocalSymbolList]
        L2 --> L3[getLocalSymbol → vcadData]
    end
    subgraph 服务端
        S1[getSymbolCategories] --> S2[getSymbolList<br/>分页/搜索]
        S2 --> S3[getSymbol → 压缩 data]
        S3 --> S4[decompressSymbolData → vcadData]
    end
    L3 --> P[parseSymbolVcadData]
    S4 --> P
    P --> M[mergeSymbolToDocument / insertSymbolInteractive]
```

## 5. 字段速览

### 本地分类 / 符号

| 字段 | 类型 | 说明 |
|---|---|---|
| 分类 | `{ id, name }` | 由 IndexedDB 生成 id |
| 符号列表项（`ILocalSymbolRecord`） | `{ id, categoryId, name, basePoint: [x,y], thumbnail（Data URL）, data: Uint8Array, createTime, updateTime }` | 列表**含**原始 `data`（可能是压缩数据），但没有 `vcadData` 字符串 |
| 符号详情 | `{ record: ILocalSymbolRecord, vcadData: string }` | `getLocalSymbol(id)` 返回包装对象（元数据在 `.record` 里，不是平铺），`vcadData` 已解压可直接给 `parseSymbolVcadData` |

### 服务端分类 / 符号

| 字段 | 类型 | 说明 |
|---|---|---|
| 分类 | `{ id, name, ... }` | 服务端 ID |
| 符号列表项 | `{ id, name, basePoint, thumbnail, createTime }` | 不含 `data` |
| 符号详情 | 列表项 + `{ data: base64Compressed }` | `decompressSymbolData` 解压才能用 |

## 红旗

- 服务端和本地是 **两套独立目录**，相同名字不会自动同步
- 服务端 `data` 是 base64+gzip，不能直接 `parseSymbolVcadData`
- 删除分类会**级联删除**其下全部符号：本地 `deleteLocalSymbolCategory` 先删该分类的 symbols 再删分类；服务端 `DeleteCategory` 直接删除整个分类目录（且仅 root 可删）
- 本地列表 `getLocalSymbolList` 返回完整记录（含 `data` 字节），但要插入仍需 `getLocalSymbol(id).vcadData`（已解压）；服务端列表不含 `data`，插入时再 `getSymbol` 单独拉
- 同步删除批量符号时，服务端可能限频；建议串行执行 + try/catch

## 参考（官方文档 MCP）

- 示例：
- `vjcad/example/insert/symbol/05managecategory.js` — 分类 CRUD
- `vjcad/example/insert/symbol/06managesymbol.js` — 符号查询 / 详情 / 删除
