Skip to content

Commit 62336af

Browse files
author
阿岳
committed
fix: 增加prg自动升级时的提醒
1 parent 1590c70 commit 62336af

File tree

1 file changed

+121
-44
lines changed

1 file changed

+121
-44
lines changed

app/src/core/Project.tsx

Lines changed: 121 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,113 @@ export class Project extends EventEmitter<{
201201
}
202202
}
203203

204+
/**
205+
* 比较两个版本号字符串(格式:x.y.z)
206+
* @param version1 版本1
207+
* @param version2 版本2
208+
* @returns 如果 version1 < version2 返回 -1,如果 version1 > version2 返回 1,如果相等返回 0
209+
*/
210+
private compareVersion(version1: string, version2: string): number {
211+
const v1Parts = version1.split(".").map(Number);
212+
const v2Parts = version2.split(".").map(Number);
213+
const maxLength = Math.max(v1Parts.length, v2Parts.length);
214+
215+
for (let i = 0; i < maxLength; i++) {
216+
const v1Part = v1Parts[i] || 0;
217+
const v2Part = v2Parts[i] || 0;
218+
if (v1Part < v2Part) return -1;
219+
if (v1Part > v2Part) return 1;
220+
}
221+
return 0;
222+
}
223+
224+
/**
225+
* 检查是否需要升级,如果需要则显示确认对话框
226+
* @param currentVersion 当前文件版本
227+
* @param latestVersion 最新版本
228+
*/
229+
private async checkAndConfirmUpgrade(currentVersion: string, latestVersion: string): Promise<void> {
230+
const needsUpgrade = this.compareVersion(currentVersion, latestVersion) < 0;
231+
232+
if (!needsUpgrade) {
233+
return;
234+
}
235+
236+
// 显示确认对话框
237+
const response = await Dialog.buttons(
238+
"检测到旧版本项目文件",
239+
`当前文件版本为 ${currentVersion},需要升级到 ${latestVersion} (是prg文件版本,非软件版本)。\n\n升级过程不可逆且可能存在风险,特别是对于大型文件,建议提前备份。是否继续升级?`,
240+
[
241+
{ id: "cancel", label: "取消", variant: "ghost" },
242+
{ id: "upgrade", label: "确认升级" },
243+
],
244+
);
245+
246+
if (response === "cancel") {
247+
// 用户取消升级,抛出错误以便调用者知道操作被取消
248+
throw new Error("用户取消了文件升级,文件未打开");
249+
}
250+
251+
// 添加延迟,确保用户看到提示并给系统时间处理
252+
await new Promise((resolve) => setTimeout(resolve, 500));
253+
}
254+
255+
/**
256+
* 解析项目文件(ZIP格式),提取所有数据
257+
* @returns 解析后的数据对象
258+
*/
259+
private async parseProjectFile(): Promise<{
260+
serializedStageObjects: any[];
261+
tags: string[];
262+
references: { sections: Record<string, string[]>; files: string[] };
263+
metadata: ProjectMetadata;
264+
}> {
265+
const fileContent = await this.fs.read(this.uri);
266+
const reader = new ZipReader(new Uint8ArrayReader(fileContent));
267+
const entries = await reader.getEntries();
268+
269+
let serializedStageObjects: any[] = [];
270+
let tags: string[] = [];
271+
let references: { sections: Record<string, string[]>; files: string[] } = { sections: {}, files: [] };
272+
let metadata: ProjectMetadata = createDefaultMetadata("2.0.0");
273+
274+
for (const entry of entries) {
275+
if (entry.filename === "stage.msgpack") {
276+
const stageRawData = await entry.getData!(new Uint8ArrayWriter());
277+
serializedStageObjects = this.decoder.decode(stageRawData) as any[];
278+
} else if (entry.filename === "tags.msgpack") {
279+
const tagsRawData = await entry.getData!(new Uint8ArrayWriter());
280+
tags = this.decoder.decode(tagsRawData) as string[];
281+
} else if (entry.filename === "reference.msgpack") {
282+
const referenceRawData = await entry.getData!(new Uint8ArrayWriter());
283+
references = this.decoder.decode(referenceRawData) as { sections: Record<string, string[]>; files: string[] };
284+
} else if (entry.filename === "metadata.msgpack") {
285+
const metadataRawData = await entry.getData!(new Uint8ArrayWriter());
286+
const decodedMetadata = this.decoder.decode(metadataRawData) as any;
287+
// 验证并规范化 metadata
288+
if (isValidMetadata(decodedMetadata)) {
289+
metadata = decodedMetadata;
290+
} else {
291+
// 如果格式不正确,使用默认值
292+
metadata = createDefaultMetadata("2.0.0");
293+
}
294+
} else if (entry.filename.startsWith("attachments/")) {
295+
const match = entry.filename.trim().match(/^attachments\/([a-zA-Z0-9-]+)\.([a-zA-Z0-9]+)$/);
296+
if (!match) {
297+
console.warn("[Project] 附件文件名不符合规范: %s", entry.filename);
298+
continue;
299+
}
300+
const uuid = match[1];
301+
const ext = match[2];
302+
const type = mime.getType(ext) || "application/octet-stream";
303+
const attachment = await entry.getData!(new BlobWriter(type));
304+
this.attachments.set(uuid, attachment);
305+
}
306+
}
307+
308+
return { serializedStageObjects, tags, references, metadata };
309+
}
310+
204311
/**
205312
* 服务加载完成后再调用
206313
*/
@@ -209,55 +316,25 @@ export class Project extends EventEmitter<{
209316
return;
210317
}
211318
try {
212-
const fileContent = await this.fs.read(this.uri);
213-
const reader = new ZipReader(new Uint8ArrayReader(fileContent));
214-
const entries = await reader.getEntries();
215-
let serializedStageObjects: any[] = [];
216-
let tags: string[] = [];
217-
let references: { sections: Record<string, string[]>; files: string[] } = { sections: {}, files: [] };
218-
let metadata: ProjectMetadata = createDefaultMetadata("2.0.0");
219-
220-
for (const entry of entries) {
221-
if (entry.filename === "stage.msgpack") {
222-
const stageRawData = await entry.getData!(new Uint8ArrayWriter());
223-
serializedStageObjects = this.decoder.decode(stageRawData) as any[];
224-
} else if (entry.filename === "tags.msgpack") {
225-
const tagsRawData = await entry.getData!(new Uint8ArrayWriter());
226-
tags = this.decoder.decode(tagsRawData) as string[];
227-
} else if (entry.filename === "reference.msgpack") {
228-
const referenceRawData = await entry.getData!(new Uint8ArrayWriter());
229-
references = this.decoder.decode(referenceRawData) as { sections: Record<string, string[]>; files: string[] };
230-
} else if (entry.filename === "metadata.msgpack") {
231-
const metadataRawData = await entry.getData!(new Uint8ArrayWriter());
232-
const decodedMetadata = this.decoder.decode(metadataRawData) as any;
233-
// 验证并规范化 metadata
234-
if (isValidMetadata(decodedMetadata)) {
235-
metadata = decodedMetadata;
236-
} else {
237-
// 如果格式不正确,使用默认值
238-
metadata = createDefaultMetadata("2.0.0");
239-
}
240-
} else if (entry.filename.startsWith("attachments/")) {
241-
const match = entry.filename.trim().match(/^attachments\/([a-zA-Z0-9-]+)\.([a-zA-Z0-9]+)$/);
242-
if (!match) {
243-
console.warn("[Project] 附件文件名不符合规范: %s", entry.filename);
244-
continue;
245-
}
246-
const uuid = match[1];
247-
const ext = match[2];
248-
const type = mime.getType(ext) || "application/octet-stream";
249-
const attachment = await entry.getData!(new BlobWriter(type));
250-
this.attachments.set(uuid, attachment);
251-
}
252-
}
319+
// 解析项目文件
320+
const { serializedStageObjects, tags, references, metadata } = await this.parseProjectFile();
321+
322+
// 检查并确认升级
323+
const currentVersion = metadata?.version || "2.0.0";
324+
const latestVersion = ProjectUpgrader.NLatestVersion;
325+
await this.checkAndConfirmUpgrade(currentVersion, latestVersion);
253326

254327
// 升级数据
255-
[serializedStageObjects, metadata] = ProjectUpgrader.upgradeNAnyToNLatest(serializedStageObjects, metadata);
328+
const [upgradedStageObjects, upgradedMetadata] = ProjectUpgrader.upgradeNAnyToNLatest(
329+
serializedStageObjects,
330+
metadata,
331+
);
256332

257-
this.stage = deserialize(serializedStageObjects, this);
333+
// 应用升级后的数据
334+
this.stage = deserialize(upgradedStageObjects, this);
258335
this.tags = tags;
259336
this.references = references;
260-
this.metadata = metadata;
337+
this.metadata = upgradedMetadata;
261338
} catch (e) {
262339
console.warn(e);
263340
}

0 commit comments

Comments
 (0)