Skip to content

Commit 9548153

Browse files
committed
✨ 添加附件系统,以及图片节点的加载和保存
1 parent 75dfbd1 commit 9548153

File tree

8 files changed

+53
-16
lines changed

8 files changed

+53
-16
lines changed

.lintstagedrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"*.{ts,tsx}": ["eslint --fix"],
3-
"*.{json,md,yaml,yml}": ["prettier --write"]
3+
"*.{json,md,yaml,yml,ts,tsx}": ["prettier --write"]
44
}

app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"lodash": "^4.17.21",
7373
"lucide-react": "^0.525.0",
7474
"md5": "^2.3.0",
75+
"mime": "^4.0.7",
7576
"next-themes": "^0.4.6",
7677
"openai": "^5.8.2",
7778
"react": "^19.1.0",

app/src/core/Project.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ import { StageObject } from "@/core/stage/stageObject/abstract/StageObject";
7373
import { projectsAtom, store } from "@/state";
7474
import { deserialize, serialize } from "@graphif/serializer";
7575
import { Decoder, Encoder } from "@msgpack/msgpack";
76-
import { Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from "@zip.js/zip.js";
76+
import { BlobReader, BlobWriter, Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from "@zip.js/zip.js";
77+
import mime from "mime";
7778
import { URI } from "vscode-uri";
7879

7980
if (import.meta.hot) {
@@ -209,16 +210,26 @@ export class Project {
209210
const fileContent = await this.fs.read(this.uri);
210211
const reader = new ZipReader(new Uint8ArrayReader(fileContent));
211212
const entries = await reader.getEntries();
213+
let serializedStageObjects: any[] = [];
212214
for (const entry of entries) {
213215
if (entry.filename === "stage.msgpack") {
214216
const stageRawData = await entry.getData!(new Uint8ArrayWriter());
215-
const decoded = this.decoder.decode(stageRawData) as any[];
216-
for (const serializedStageObject of decoded) {
217-
const stageObject = deserialize(serializedStageObject, this);
218-
this.stage.push(stageObject);
217+
serializedStageObjects = this.decoder.decode(stageRawData) as any[];
218+
} else if (entry.filename.startsWith("attachments/")) {
219+
const match = entry.filename.trim().match(/^attachments\/([a-zA-Z0-9-]+)\.([a-zA-Z0-9]+)$/);
220+
if (!match) {
221+
console.warn("[Project] 附件文件名不符合规范: %s", entry.filename);
222+
continue;
219223
}
224+
const uuid = match[1];
225+
const ext = match[2];
226+
const type = mime.getType(ext) || "application/octet-stream";
227+
const attachment = await entry.getData!(new BlobWriter(type));
228+
this.attachments.set(uuid, attachment);
220229
}
221230
}
231+
this.stage = serializedStageObjects.map((it) => deserialize(it, this));
232+
this.state = ProjectState.Saved;
222233
}
223234
}
224235

@@ -303,6 +314,10 @@ export class Project {
303314
const uwriter = new Uint8ArrayWriter();
304315
const writer = new ZipWriter(uwriter);
305316
writer.add("stage.msgpack", new Uint8ArrayReader(encodedStage));
317+
// 添加附件
318+
for (const [uuid, attachment] of this.attachments.entries()) {
319+
writer.add(`attachments/${uuid}.${mime.getExtension(attachment.type)}`, new BlobReader(attachment));
320+
}
306321
await writer.close();
307322
const fileContent = await uwriter.getData();
308323
await this.fs.write(this.uri, fileContent);

app/src/core/render/canvas2d/entityRenderer/EntityRenderer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export class EntityRenderer {
246246
);
247247
} else if (imageNode.state === "notFound") {
248248
this.project.textRenderer.renderTextFromCenter(
249-
"not found",
249+
`not found ${imageNode.attachmentId}`,
250250
this.project.renderer.transformWorld2View(imageNode.rectangle.center),
251251
20 * this.project.camera.currentScale,
252252
this.project.stageStyleManager.currentStyle.StageObjectBorder,

app/src/core/service/GlobalMenu.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,23 @@ export async function onOpenFile() {
457457
const t = performance.now();
458458
loadAllServices(project);
459459
const loadServiceTime = performance.now() - t;
460-
await project.init();
461-
const readFileTime = performance.now() - t;
462-
store.set(projectsAtom, [...store.get(projectsAtom), project]);
463-
store.set(activeProjectAtom, project);
464-
Telemetry.event("打开文件", {
465-
loadServiceTime,
466-
readFileTime,
460+
toast.promise(project.init(), {
461+
loading: "正在打开文件...",
462+
success: () => {
463+
const readFileTime = performance.now() - t;
464+
store.set(projectsAtom, [...store.get(projectsAtom), project]);
465+
store.set(activeProjectAtom, project);
466+
Telemetry.event("打开文件", {
467+
loadServiceTime,
468+
readFileTime,
469+
});
470+
return `耗时 ${readFileTime} ms,共 ${project.stage.length} 个舞台对象,${project.attachments.size} 个附件`;
471+
},
472+
error: (e) => {
473+
Telemetry.event("打开文件失败", {
474+
error: String(e),
475+
});
476+
return `读取时发生错误,已发送错误报告,可在群内联系开发者\n${String(e)}`;
477+
},
467478
});
468479
}

app/src/core/stage/stageManager/StageHistoryManager.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ export class HistoryManager {
8787
const data = patches.reduce((acc, patch) => {
8888
return applyPatch(acc, patch).newDocument;
8989
}, this.initialStage);
90-
console.log(data);
9190
// 反序列化得到舞台对象
9291
const stage = deserialize(data);
9392
return stage;

packages/serializer/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function deserialize(json: any, extra?: any): any {
8585
const className = json._;
8686
const class_ = classes.get(className);
8787
if (!class_) {
88-
throw TypeError(`[Serializer] Cannot find class ${class_}`);
88+
throw TypeError(`[Serializer] Cannot find class ${class_} of ${JSON.stringify(json)}`);
8989
}
9090
// 先把json中有_的值反序列化
9191
for (const key in json) {

pnpm-lock.yaml

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)