历史浏览与删除
文档:
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