fix(web): 本地优先保存与 design 页体验修复

- 保存先写本地缓存,登录后可选云端同步;退出登录不再因文件操作跳转登录

- 修复 Layui 遮罩残留、design2 保存后线条、toast 被 finally 提前关闭

- 保存过程恢复 loading spinner;成功提示 2.5 秒

- 云端 payload 瘦身与体积超限提示;后端 schema 迁移与 FileService 容错

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
24kycj
2026-06-24 19:24:34 +08:00
parent 4d19d7e814
commit 5fb269cc0a
36 changed files with 894 additions and 358 deletions
+75 -25
View File
@@ -88,22 +88,29 @@
}
});
if (hidden.length) canvas.renderAll();
window._soonSkipDesign1CdMask = true;
var mult = 0.18;
var quality = 0.72;
var url = '';
for (var i = 0; i < 3; i++) {
try {
var candidate = canvas.toDataURL({ format: 'jpeg', quality: quality, multiplier: mult });
if (candidate && candidate.indexOf('data:image/') === 0 && candidate.length <= THUMB_MAX) {
url = candidate;
break;
}
} catch (e) { /* ignore */ }
quality -= 0.18;
mult -= 0.04;
try {
for (var i = 0; i < 3; i++) {
try {
var candidate = canvas.toDataURL({ format: 'jpeg', quality: quality, multiplier: mult });
if (candidate && candidate.indexOf('data:image/') === 0 && candidate.length <= THUMB_MAX) {
url = candidate;
break;
}
} catch (e) { /* ignore */ }
quality -= 0.18;
mult -= 0.04;
}
} finally {
window._soonSkipDesign1CdMask = false;
}
hidden.forEach(function (obj) { obj.visible = true; });
if (hidden.length) canvas.renderAll();
canvas.renderAll();
if (typeof window.soonClearFabricOverlay === 'function') window.soonClearFabricOverlay(canvas);
if (canvas.requestRenderAll) canvas.requestRenderAll();
return url;
}
@@ -134,8 +141,20 @@
return soonEnsureSoonExt(name);
}
function dismissLayerMask() {
if (typeof window.soonCleanupLayerMask === 'function') {
window.soonCleanupLayerMask();
return;
}
soonHideOpenFileLoading();
invokeLayerCleanup();
}
function soonReportSaveError(err) {
if (typeof window.soonFinishSaveUi === 'function') window.soonFinishSaveUi();
else dismissLayerMask();
if (err && err.conflictSynced) return;
if (err && err.apiNotified) return;
if (typeof window.soonShowApiError === 'function') {
window.soonShowApiError({
status: err && err.status,
@@ -149,11 +168,27 @@
function soonWriteSoonContentWeb(fp, content, prevOpenKey, onDone, onError) {
if (!window.platformBridge || !window.platformBridge.writeFile) return false;
window.platformBridge.writeFile(fp, content).then(function (res) {
if (typeof window.soonShowOpenFileLoading === 'function') window.soonShowOpenFileLoading();
var writePromise;
try {
writePromise = window.platformBridge.writeFile(fp, content);
} catch (syncErr) {
dismissLayerMask();
if (typeof onError === 'function') onError(syncErr);
else soonReportSaveError(syncErr);
return true;
}
if (!writePromise || typeof writePromise.then !== 'function') {
dismissLayerMask();
return true;
}
writePromise.then(function (res) {
if (typeof onDone === 'function') onDone(res, prevOpenKey);
}).catch(function (err) {
if (typeof onError === 'function') onError(err);
else soonReportSaveError(err);
}).finally(function () {
dismissLayerMask();
});
return true;
}
@@ -656,37 +691,52 @@
});
}
function invokeLayerCleanup() {
if (typeof window.soonCleanupLayerMask === 'function') {
window.soonCleanupLayerMask();
}
}
function soonReportOpenLoadError(message) {
soonHideOpenFileLoading();
invokeLayerCleanup();
soonToast(message || '文件加载失败', 'error');
}
function soonShowOpenFileLoading() {
if (typeof layer === 'undefined' || !layer.load) return;
soonHideOpenFileLoading();
window._soonOpenLoadIdx = layer.load(1, { shade: [0.12, '#000'] });
window._soonOpenLoadIdx = layer.load(1, { shade: 0 });
}
function soonHideOpenFileLoading() {
if (window._soonOpenLoadIdx == null) return;
if (typeof layer !== 'undefined' && layer.close) layer.close(window._soonOpenLoadIdx);
if (typeof layer !== 'undefined' && layer.closeAll) {
layer.closeAll('loading');
}
if (window._soonOpenLoadIdx != null && typeof layer !== 'undefined' && layer.close) {
try { layer.close(window._soonOpenLoadIdx); } catch (e) { /* ignore */ }
}
window._soonOpenLoadIdx = null;
invokeLayerCleanup();
}
function soonToast(message, type) {
if (typeof window.soonToast === 'function') window.soonToast(message, type);
}
function soonRequireLogin(actionLabel) {
function soonRequireLogin(actionLabel, options) {
options = options || {};
if (soonGetAccessToken()) return true;
var label = actionLabel || '继续';
soonToast('请先登录后再' + label, 'warn');
if (typeof window.soonRedirectToLogin === 'function') {
setTimeout(function () { window.soonRedirectToLogin(); }, 600);
} else if (typeof window.redirectToLogin === 'function') {
setTimeout(function () { window.redirectToLogin(); }, 600);
} else {
window.location.href = 'login.web.html';
soonToast('请先登录后再' + (label || '操作'), 'warn');
if (options.redirect) {
if (typeof window.soonRedirectToLogin === 'function') {
setTimeout(function () { window.soonRedirectToLogin(); }, 600);
} else if (typeof window.redirectToLogin === 'function') {
setTimeout(function () { window.redirectToLogin(); }, 600);
} else {
window.location.href = 'login.web.html';
}
}
return false;
}
@@ -724,8 +774,8 @@
else if (info.status === 409) kind = 'warn';
else if (info.status === 413) kind = 'warn';
soonToast(info.message, kind);
if (info.status === 401) {
soonRequireLogin('操作');
if (info.status === 401 && info.requireLogin) {
soonRequireLogin('操作', { redirect: true });
}
}