唯杰地图 logo唯杰地图
VJMAP
EN

历史浏览与删除

vjcad/references/version/history.md 5.2 KB136 行
原文

文档:vjcad/doc/version/versioning.md 示例:vjcad/example/version/04versionhistory.js

1. 取历史

listBranches 收 一个对象参数(不是位置参数),返回 IBranchInfo[]:

const drawingManager = new DrawingManagerService();

const branches = await drawingManager.listBranches({
    type: 'imports', mapid: 'test', version: 'v1'
});
branches.forEach(b => {
    // IBranchInfo: name / createdAt / createdBy / sourceInfo{branch,patchId} / patchCount / latestPatchId / patches
    const src = b.sourceInfo ? `(基于 ${b.sourceInfo.branch}@${b.sourceInfo.patchId})` : '';
    console.log(`分支 ${b.name}${src}`);
    (b.patches || []).forEach((p, i) => {
        // IPatchInfo: id / parentId / time / author / remark
        const t = p.time ? new Date(p.time).toLocaleString() : '';
        console.log(`  ${i + 1}. ${p.id} by ${p.author ?? ''} @ ${t} - ${p.remark || ''}`);
    });
});

完整代码:vjcad/example/version/04versionhistory.js

patches 数组按时间顺序排列;最后一条就是该分支当前 head(也即 b.latestPatchId)。

2. 切换到某个 patch(只读对照)

没有 openDbDoc({mapid, lastPatchId}) 这种调用——真实流程是 openDrawing 取数据 + openDbDoc(file, data, readOnly) 加载(同 OpenFromServerCommand):

const openResult = await drawingManager.openDrawing({
    type: 'imports', mapid: 'test', version: 'v1',
    branch: 'main',
    patchId: 'p3',             // 任意历史 patch(id 形如 p1、p2…);省略则取最新
    readOnly: true,
});
if (openResult.success) {
    const virtualFile = new File([openResult.webcadJson], 'history_view', { type: 'application/json' });
    await Engine.view.openDbDoc(virtualFile, openResult.webcadData, true);
    // 如需保留来源信息(再保存时以该 patch 为 parent):
    Engine.currentDoc.serverSource = {
        type: 'imports', mapid: 'test', version: 'v1',
        branchName: 'main',
        lastPatchId: openResult.latestPatchId || 'p3',
    };
}

历史 patch 默认不应直接编辑;如需基于历史出发新建分支,用 createBranch({ branchName, sourceBranch, sourcePatchId: 'p3' })——注意字段名是 sourcePatchId 不是 parentPatchId。

3. 删除补丁

deletePatch 必填 type + patchId;分支字段名是 branch:

await drawingManager.deletePatch({
    type:    'imports',
    mapid:   'test',
    version: 'v1',
    branch:  'main',          // 不是 branchName
    patchId: 'p3'
});

⚠️ 删除补丁是 危险操作:服务端会删除指定 patch 及其之后的全部 patch(链被截断到它之前,不会留下断链),返回 { status, deletedPatchId, branch };patchId: 'base' 会被拒绝(Cannot delete base version)。只想撤销最近一次保存就删 head 补丁。

4. 删除分支

deleteBranch 必填 type + branchName:

await drawingManager.deleteBranch({
    type: 'imports', mapid: 'test', version: 'v1',
    branchName: 'feature-abc'
});

删除分支会连带删除该分支的所有补丁。main 不可删(服务端返回 Cannot delete main branch);要删 main 只能用 deleteDrawing 删除整张图纸。

5. 数据结构字段

源码真实接口:

interface IBranchInfo {
    name: string;                    // 分支名(不是 branchName)
    createdAt: string;
    createdBy: string;
    sourceInfo?: { branch: string; patchId: string };   // 源分支@patch
    description?: string;
    patchCount: number;
    latestPatchId: string;
    patches?: IPatchInfo[];
    drawingName?: string;
}

interface IPatchInfo {
    id: string;                      // patch ID(不是 patchId)
    parentId?: string;
    time?: string;                   // 时间字符串(不是 timestamp number)
    author?: string;                 // 作者(不是 userId)
    remark?: string;                 // 备注(不是 message)
    editAreas?: IEditArea[];         // 瓦片编辑区(tile 模式恢复用)
    editLayers?: string[];
    tileAlpha?: number;
}

6. 与时间机器的对应

把 listBranches + openDrawing({ patchId }) 组合起来,可以做:

  • 历史时间轴
  • 任意点 checkout 出来对比
  • 找到回退点 → createBranch({ sourcePatchId }) → 在该点出新分支

红旗

  • deletePatch 删除的是"该 patch 及其后全部",删中间补丁等于把分支回退到它之前;只想保留历史又要回退,用 createBranch({ sourcePatchId }) 从回退点出新分支
  • main 分支不可删,服务端硬性拒绝;只能 deleteDrawing 删整图
  • listBranches 数据量大时(年单位、几千补丁)建议后端分页或按时间过滤
  • 不需要前端逐个回放补丁:openDrawing({ branch, patchId }) 由服务端合成(带缓存)并直接返回该补丁处的完整图纸
  • 如果只想撤销当前未保存改动,请用 Undo(参见 undo/),不要去 deletePatch

参考(官方文档 MCP)

  • 文档:vjcad/doc/version/versioning.md
  • 示例:vjcad/example/version/04versionhistory.js
  • 源码:DrawingManagerService.listBranches/openDrawing/deletePatch/deleteBranch、ServiceInterface.IBranchInfo/IPatchInfo