fix(web): 修复 .soon/模板加载、旧文件兼容与另存为离开提示

- 删除 design1 ui 遗留代码,修复加载竞态与新建不弹保存提示
- cloud-files 归一化旧版 .soon,IndexedDB 写入完成后再跳转设计页
- 模板/本地 .soon 首次保存须另存为,离开前统一确认
- 发版缓存 bust(version.js、soon-cache.js)及宝塔 Nginx 配置文档

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
24kycj
2026-06-29 00:30:20 +08:00
parent efeb3bcc41
commit ce76bb8018
27 changed files with 648 additions and 254 deletions
+51 -40
View File
@@ -78,29 +78,7 @@ function soonDesign1ApplyDiscAlpha(tctx, w, h, holeDiameterMm) {
tctx.restore();
}
/** 圆外与中心孔铺画布底色,保留环形内容(缩略图用) */
function soonDesign1ApplyDiscMatte(tctx, w, h, holeDiameterMm, color) {
var snap = document.createElement('canvas');
snap.width = w;
snap.height = h;
snap.getContext('2d').drawImage(tctx.canvas, 0, 0);
tctx.fillStyle = color;
tctx.fillRect(0, 0, w, h);
tctx.save();
var cx = w / 2;
var cy = h / 2;
var rOuter = w / 2;
var rInner = rOuter * (holeDiameterMm / 120);
tctx.beginPath();
tctx.arc(cx, cy, rOuter, 0, Math.PI * 2);
tctx.moveTo(cx + rInner, cy);
tctx.arc(cx, cy, rInner, 0, Math.PI * 2, true);
tctx.clip('evenodd');
tctx.drawImage(snap, 0, 0);
tctx.restore();
}
function soonDesign1CaptureCanvasRect(canvas, outW, outH, format, quality, clipDisc, discMatte) {
function soonDesign1CaptureCanvasRect(canvas, outW, outH, format, quality, clipDisc) {
var bg = window.background_image1 || window.background_image;
if (!canvas || !bg) return '';
var srcEl = canvas.lowerCanvasEl;
@@ -121,9 +99,7 @@ function soonDesign1CaptureCanvasRect(canvas, outW, outH, format, quality, clipD
bg.left * retina, bg.top * retina, sw * retina, sh * retina,
0, 0, outW, outH
);
if (discMatte) {
soonDesign1ApplyDiscMatte(tctx, outW, outH, soonDesign1GetHoleDiameterMm(canvas), discMatte);
} else if (clipDisc && format !== 'jpeg') {
if (clipDisc && format !== 'jpeg') {
soonDesign1ApplyDiscAlpha(tctx, outW, outH, soonDesign1GetHoleDiameterMm(canvas));
}
if (format === 'jpeg') return tmp.toDataURL('image/jpeg', quality == null ? 0.75 : quality);
@@ -133,14 +109,33 @@ function soonDesign1CaptureCanvasRect(canvas, outW, outH, format, quality, clipD
/** 导出/打印:跳过编辑器暗蒙版,按光盘环形裁剪 */
function soonDesign1CaptureDiscPng(canvas, outW, outH) {
window._soonSkipDesign1CdMask = true;
if (canvas.discardActiveObject) canvas.discardActiveObject();
canvas.renderAll();
var url = soonDesign1CaptureCanvasRect(canvas, outW, outH, 'png', null, true);
window._soonSkipDesign1CdMask = false;
canvas.renderAll();
return url;
try {
if (canvas.discardActiveObject) canvas.discardActiveObject();
canvas.renderAll();
return soonDesign1CaptureCanvasRect(canvas, outW, outH, 'png', null, true);
} finally {
window._soonSkipDesign1CdMask = false;
canvas.renderAll();
}
}
/** 本地 .soon 不存 output 大图字段,避免文件过大导致缓存/加载失败 */
function soonStripDesign1HeavyFields(con_o) {
if (!con_o) return con_o;
delete con_o.frontColorPic;
delete con_o.backColorPic;
delete con_o.frontBlackPic;
delete con_o.backBlackPic;
delete con_o.frontData;
delete con_o.backData;
delete con_o.backDisplayPic;
if (typeof con_o.frontDisplayPic === 'string' && con_o.frontDisplayPic.length > 120000) {
delete con_o.frontDisplayPic;
}
return con_o;
}
window.soonStripDesign1HeavyFields = soonStripDesign1HeavyFields;
function soonBuildDesign1SavePreviewPic(canvas) {
var THUMB_MAX = 102400;
var c1 = window.canvas1;
@@ -159,7 +154,7 @@ function soonBuildDesign1SavePreviewPic(canvas) {
var url = '';
var sizes = [280, 240, 200, 180, 160];
for (var i = 0; i < sizes.length; i++) {
url = soonDesign1CaptureCanvasRect(canvas, sizes[i], sizes[i], 'png', null, false, '#31373D');
url = soonDesign1CaptureCanvasRect(canvas, sizes[i], sizes[i], 'png', null, true);
if (url && url.indexOf('data:image/') === 0 && url.length <= THUMB_MAX) break;
url = '';
}
@@ -1223,22 +1218,25 @@ window.regenerateQrCodesAndBarcodes = function regenerateQrCodesAndBarcodes(canv
// 使用 window.openFile 避免与浏览器原生的 window.open 冲突
window.openFile = function open(file, jAlready) {
if (!file) return;
if (typeof window.soonOnOpenDesignFile === 'function') window.soonOnOpenDesignFile(file);
if (typeof window.soonBindFileMeta === 'function') window.soonBindFileMeta(file);
function doOpenWithJson(j) {
if (!j || !background_image) {
if (typeof window.soonNormalizeSoonJson === 'function') {
j = window.soonNormalizeSoonJson(j);
}
if (!j) {
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
return;
}
if (!j.f || !j.f.objects || !Array.isArray(j.f.objects) || j.f.objects.length === 0) {
function runOpen() {
var bgRef = window.background_image1 || window.background_image;
if (!bgRef) {
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
return;
}
if (!j.b || !j.b.objects || !Array.isArray(j.b.objects) || j.b.objects.length === 0) {
j.b = { version: '4.6.0', objects: [], hoverCursor: 'move' };
}
openAs.name = file;
var left = background_image.left;
var top = background_image.top;
var left = bgRef.left;
var top = bgRef.top;
var new_left = j.f.objects[0].left;
var new_top = j.f.objects[0].top;
for (var i = 0; i < j.f.objects.length; i++) {
@@ -1311,6 +1309,14 @@ window.openFile = function open(file, jAlready) {
if (typeof window.soonRecentUpsertFromOpen === 'function') window.soonRecentUpsertFromOpen(file, j);
}
});
}
if (typeof window.soonRunWhenDesignBgReady === 'function') {
window.soonRunWhenDesignBgReady(runOpen, function () {
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
});
} else {
runOpen();
}
}
if (arguments.length >= 2 && jAlready) {
doOpenWithJson(jAlready);
@@ -1384,6 +1390,7 @@ function cleanupSrcFields(jsonObjects, objsArray) {
function applyCloudWriteResult(result, fallbackName) {
if (result && result.fileKey) {
openAs.name = result.fileKey;
if (typeof window.soonMarkSaveInPlace === 'function') window.soonMarkSaveInPlace(result.fileKey);
return result.fileKey;
}
return fallbackName;
@@ -1467,6 +1474,7 @@ function saveAs(op1, callback) {
if (typeof window.soonApplySavePreview === 'function') window.soonApplySavePreview(con_o, canvas1);
if (typeof window.soonRefreshDesignCanvases === 'function') window.soonRefreshDesignCanvases();
con_o.soonType = 1;
soonStripDesign1HeavyFields(con_o);
var dialogApi = (typeof dialog !== 'undefined' && dialog) ? dialog : (window.platformBridge && window.platformBridge.showSaveDialog ? { showSaveDialog: function(opts) { return window.platformBridge.showSaveDialog(opts); } } : null);
if (!dialogApi) return;
dialogApi.showSaveDialog({
@@ -1488,6 +1496,7 @@ function saveAs(op1, callback) {
if (fs) {
fs.writeFileSync(result.filePath || fp, content, 'utf8');
openAs.name = result.filePath || fp;
if (typeof window.soonMarkSaveInPlace === 'function') window.soonMarkSaveInPlace(openAs.name);
layer.msg(language_str("saveSucc") + openAs.name);
saveHistory();
if (callback && typeof callback === 'function') callback();
@@ -1535,6 +1544,7 @@ function save(op1, callback) {
if (typeof window.soonApplySavePreview === 'function') window.soonApplySavePreview(con_o, canvas1);
if (typeof window.soonRefreshDesignCanvases === 'function') window.soonRefreshDesignCanvases();
con_o.soonType = 1;
soonStripDesign1HeavyFields(con_o);
var content = JSON.stringify(con_o);
var needsDialog = typeof window.soonNeedsSaveDialog === 'function'
? window.soonNeedsSaveDialog(openAs.name)
@@ -1573,6 +1583,7 @@ function save(op1, callback) {
if (fs) {
fs.writeFileSync(result.filePath || fp, content, 'utf8');
openAs.name = result.filePath || fp;
if (typeof window.soonMarkSaveInPlace === 'function') window.soonMarkSaveInPlace(openAs.name);
layer.msg(language_str("saveSucc") + openAs.name);
saveHistory();
if (callback && typeof callback === 'function') callback();