Web 端数据交互与 design2 布局修复

统一门户 JSON 契约:新增 GET /templates/{id},模板/云文件/保存/打开走虚拟 key;
layer 保存弹层替代 prompt,本地 .soon 已登录后台 POST 登记;修复保存静默失败与 design2 全宽布局。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
24kycj
2026-06-09 01:20:34 +08:00
parent ebe191b06d
commit 877fd278c2
27 changed files with 1232 additions and 326 deletions
+200 -19
View File
@@ -2,9 +2,23 @@
'use strict';
var FILE_PREFIX = 'soondesign_file:';
var TEMPLATE_PREFIX = 'soondesign_template:';
function soonParseTemplateKey(key) {
if (!key || typeof key !== 'string') return null;
var m = key.match(/^soondesign_template:(\d+)$/);
if (!m) return null;
return { id: parseInt(m[1], 10) };
}
function soonMakeTemplateKey(id) {
return TEMPLATE_PREFIX + id;
}
function soonIsWebPortal() {
return typeof window !== 'undefined' && window.platformBridge && !window.fs;
if (typeof window === 'undefined') return false;
if (window.SOON_DEPLOY_CONFIG) return true;
return !!(window.platformBridge && window.fs == null);
}
function soonGetAccessToken() {
@@ -31,6 +45,10 @@
var meta = window._soonFileMeta;
return (meta && meta.name) ? meta.name : 'design.soon';
}
if (n.indexOf(TEMPLATE_PREFIX) === 0) {
var tpl = soonParseTemplateKey(n);
return tpl ? ('template-' + tpl.id + '.soon') : 'template.soon';
}
if (n.indexOf('soondesign_session:') === 0) {
n = n.replace(/^soondesign_session:/, '');
}
@@ -45,8 +63,68 @@
return soonMakeFileKey(data.id, data.version);
}
function soonSyncOpenNavigation(fileKey, type) {
if (typeof sessionStorage === 'undefined') {
if (!fileKey || fileKey.indexOf(FILE_PREFIX) !== 0) window._soonFileMeta = null;
return;
}
try {
if (fileKey) {
sessionStorage.setItem('soondesign_open_file', fileKey);
sessionStorage.setItem('soondesign_open_type', String(type || 1));
if (fileKey.indexOf(FILE_PREFIX) === 0 && window._soonFileMeta) {
sessionStorage.setItem('soondesign_open_meta', JSON.stringify(window._soonFileMeta));
} else {
sessionStorage.removeItem('soondesign_open_meta');
if (fileKey.indexOf(FILE_PREFIX) !== 0) window._soonFileMeta = null;
}
} else {
sessionStorage.removeItem('soondesign_open_file');
sessionStorage.removeItem('soondesign_open_type');
sessionStorage.removeItem('soondesign_open_meta');
window._soonFileMeta = null;
}
} catch (e) { /* ignore quota */ }
}
function soonResolveOpenFileKey(getParams) {
var params = typeof getParams === 'function' ? getParams() : null;
if (!params || typeof params.has !== 'function') return '';
var file = params.has('file') ? (params.get('file') || '') : null;
if (file === null && typeof sessionStorage !== 'undefined') {
try {
file = sessionStorage.getItem('soondesign_open_file') || '';
if (file) {
sessionStorage.removeItem('soondesign_open_file');
sessionStorage.removeItem('soondesign_open_type');
}
} catch (e) {
file = '';
}
}
return file || '';
}
function soonConsumeOpenMeta(fileKey) {
if (!fileKey || fileKey.indexOf(FILE_PREFIX) !== 0) {
window._soonFileMeta = null;
return;
}
if (typeof sessionStorage === 'undefined') return;
try {
var metaRaw = sessionStorage.getItem('soondesign_open_meta');
if (metaRaw) {
window._soonFileMeta = JSON.parse(metaRaw);
sessionStorage.removeItem('soondesign_open_meta');
}
} catch (e) { /* ignore */ }
}
function soonBindFileMeta(fileKey, opts) {
if (!fileKey || fileKey.indexOf(FILE_PREFIX) !== 0) return;
if (!fileKey || fileKey.indexOf(FILE_PREFIX) !== 0) {
window._soonFileMeta = null;
return;
}
var parsed = soonParseFileKey(fileKey);
if (!parsed) return;
var prev = window._soonFileMeta || {};
@@ -137,16 +215,22 @@
soonApplyMembership(null);
return Promise.resolve(_membership);
}
var url = soonApiBase() + '/plans/me';
var url = soonApiBase() + '/auth/me';
var fetchFn = typeof window.soonAuthedFetch === 'function'
? window.soonAuthedFetch(url, { headers: { Accept: 'application/json' } })
: fetch(url, { headers: { Authorization: 'Bearer ' + soonGetAccessToken(), Accept: 'application/json' } });
_membership.loading = fetchFn
.then(function (r) { return r.json(); })
.then(function (r) {
if (r.status === 401) {
soonApplyMembership(null);
return null;
}
return r.json();
})
.then(function (j) {
if (j && j.ok && j.data) {
soonApplyMembership(j.data.membership || j.data);
} else {
soonApplyMembership(j.data);
} else if (j !== null) {
soonApplyMembership(null);
}
return _membership;
@@ -184,20 +268,27 @@
}
return;
}
if (soonIsMember()) {
onAllowed();
function allowOrActivate() {
if (soonIsMember()) {
onAllowed();
return;
}
if (typeof window.soonShowActivateGate === 'function') {
window.soonShowActivateGate({
reason: actionLabel || '导出或打印',
onSuccess: function () {
onAllowed();
},
});
} else {
soonToast('请先激活会员后再' + (actionLabel || '操作'), 'warn');
}
}
if (!_membership.loaded) {
soonLoadMembership(false).then(allowOrActivate);
return;
}
if (typeof window.soonShowActivateGate === 'function') {
window.soonShowActivateGate({
reason: actionLabel || '导出或打印',
onSuccess: function () {
onAllowed();
},
});
} else {
soonToast('请先激活会员后再' + (actionLabel || '操作'), 'warn');
}
allowOrActivate();
}
function soonGuardCloudSave() {
@@ -223,7 +314,11 @@
function soonOpenSoonJsonLocally(j, fileName) {
var key = soonPutSoonSession(j, fileName);
if (!key) return '';
if (!key) {
soonToast('无法打开文件(存储空间不足)', 'error');
return '';
}
soonScheduleCloudImport(key, fileName);
var type = soonSoonTypeFromJson(j);
if (window.platformBridge && window.platformBridge.openDesignPage) {
window.platformBridge.openDesignPage(key, type);
@@ -231,6 +326,75 @@
return key;
}
var PENDING_IMPORT_KEY = 'soondesign_pending_import';
function soonScheduleCloudImport(sessionKey, fileName) {
if (!soonGetAccessToken() || !sessionKey) return;
if (sessionKey.indexOf('soondesign_session:') !== 0) return;
try {
sessionStorage.setItem(PENDING_IMPORT_KEY, JSON.stringify({
sessionKey: sessionKey,
name: soonNormalizeSoonName(fileName || 'design.soon'),
at: Date.now()
}));
} catch (e) { /* ignore */ }
}
function soonClearPendingImport() {
try { sessionStorage.removeItem(PENDING_IMPORT_KEY); } catch (e) { /* ignore */ }
}
function soonTryConsumeCloudImport(currentFileKey) {
if (!currentFileKey || currentFileKey.indexOf('soondesign_session:') !== 0) return;
if (!soonGetAccessToken()) return;
if (typeof window.openAs !== 'undefined' && window.openAs && window.openAs.name &&
window.openAs.name.indexOf(FILE_PREFIX) === 0) {
soonClearPendingImport();
return;
}
var pendingRaw;
try {
pendingRaw = sessionStorage.getItem(PENDING_IMPORT_KEY);
} catch (e) {
return;
}
if (!pendingRaw) return;
var pending;
try {
pending = JSON.parse(pendingRaw);
} catch (e) {
try { sessionStorage.removeItem(PENDING_IMPORT_KEY); } catch (e2) { /* ignore */ }
return;
}
if (!pending || pending.sessionKey !== currentFileKey) return;
try { sessionStorage.removeItem(PENDING_IMPORT_KEY); } catch (e) { /* ignore */ }
var jsonRaw;
try {
jsonRaw = sessionStorage.getItem(currentFileKey);
if (!jsonRaw && typeof localStorage !== 'undefined') jsonRaw = localStorage.getItem(currentFileKey);
} catch (e) {
return;
}
if (!jsonRaw) return;
var bridge = window.platformBridge;
if (!bridge || typeof bridge.importSoonFile !== 'function') return;
bridge.importSoonFile(pending.name || 'design.soon', jsonRaw).then(function (res) {
if (res && res.fileKey && typeof window.openAs !== 'undefined' && window.openAs) {
window.openAs.name = res.fileKey;
}
}).catch(function (err) {
if (err && err.status) return;
soonToast((err && err.message) ? err.message : '云端登记失败,可稍后保存重试', 'warn');
});
}
function soonReportOpenLoadError(message) {
soonToast(message || '文件加载失败', 'error');
}
function soonToast(message, type) {
if (typeof window.soonToast === 'function') window.soonToast(message, type);
}
@@ -289,6 +453,14 @@
function soonDisplayFileName(pathOrKey) {
if (!pathOrKey) return '';
if (pathOrKey.indexOf(TEMPLATE_PREFIX) === 0) {
var tplMeta = window._soonTemplateMeta;
var tplParsed = soonParseTemplateKey(pathOrKey);
if (tplMeta && tplParsed && tplMeta.id === tplParsed.id && tplMeta.name) {
return tplMeta.name;
}
return tplParsed ? ('模板 #' + tplParsed.id) : pathOrKey;
}
if (pathOrKey.indexOf(FILE_PREFIX) === 0) {
var meta = window._soonFileMeta;
if (meta && meta.name) return meta.name;
@@ -333,12 +505,21 @@
window.soonNormalizeSoonName = soonNormalizeSoonName;
window.soonApplyCloudMeta = soonApplyCloudMeta;
window.soonBindFileMeta = soonBindFileMeta;
window.soonSyncOpenNavigation = soonSyncOpenNavigation;
window.soonResolveOpenFileKey = soonResolveOpenFileKey;
window.soonConsumeOpenMeta = soonConsumeOpenMeta;
window.soonFormatOpenTitle = soonFormatOpenTitle;
window.soonGuardCloudSave = soonGuardCloudSave;
window.soonGuardPreviewDeliver = soonGuardPreviewDeliver;
window.soonHandlePayReturn = soonHandlePayReturn;
window.soonOpenSoonJsonLocally = soonOpenSoonJsonLocally;
window.soonPutSoonSession = soonPutSoonSession;
window.soonScheduleCloudImport = soonScheduleCloudImport;
window.soonTryConsumeCloudImport = soonTryConsumeCloudImport;
window.soonClearPendingImport = soonClearPendingImport;
window.soonReportOpenLoadError = soonReportOpenLoadError;
window.soonParseTemplateKey = soonParseTemplateKey;
window.soonMakeTemplateKey = soonMakeTemplateKey;
window.soonSoonTypeFromJson = soonSoonTypeFromJson;
window.soonLoadMembership = soonLoadMembership;
window.soonApplyMembership = soonApplyMembership;
+1 -1
View File
@@ -260,7 +260,7 @@
return '未获取到支付信息';
}
function payEmptyStateHtml(channel) {
function paySheetHtml(opts) {
opts = opts || {};
var resumeOrderNo = opts.orderNo || null;
var channels = opts.displayChannels || _displayChannels;
+10 -22
View File
@@ -6,7 +6,9 @@ $("#object_attribute").css("height", "470px");
$("#obj_list").css("height", document.body.clientHeight - 520);
$(".obj_list").css("height", $("#obj_list").height() - 32);
$(".main").show();
var mainEl = document.querySelector('.layui-fluid.main');
if (mainEl) mainEl.style.display = 'flex';
else $(".main").show();
$(".canvas_box").css("height", document.body.clientHeight - 100);
zoom = $(".canvas_bg_img").width() / 2787
$("#canvas1").attr("width", $(".canvas_box").width() / zoom);
@@ -259,7 +261,7 @@ if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
applySysLan(window.platformBridge.getLocale());
}
function onCloseConfirm() {
layer.confirm('<font style="color:black">' + language_str("whetherSave") + '</font>', {
layer.confirm(language_str("whetherSave"), {
btn: [language_str("save"), language_str("noSave"), language_str("cancel")]
, btn3: function (index, layero) {}
}, function (index, layero) {
@@ -418,28 +420,14 @@ function addBackground() {
recordObjs2.push(JSON.stringify(objs2));
recordJson2.push(canvas2.toJSON(TO_JSON_PROPERTIES));
let file = GetFile().get('file');
if (!file && typeof sessionStorage !== 'undefined') {
try {
file = sessionStorage.getItem('soondesign_open_file');
if (file) {
sessionStorage.removeItem('soondesign_open_file');
sessionStorage.removeItem('soondesign_open_type');
}
} catch (e) {}
}
var file = typeof window.soonResolveOpenFileKey === 'function'
? window.soonResolveOpenFileKey(GetFile)
: (GetFile().get('file') || '');
if (file && file != 'empty') {
if (file.indexOf('soondesign_file:') === 0 && typeof sessionStorage !== 'undefined') {
try {
var metaRaw = sessionStorage.getItem('soondesign_open_meta');
if (metaRaw) {
window._soonFileMeta = JSON.parse(metaRaw);
sessionStorage.removeItem('soondesign_open_meta');
}
} catch (e) {}
if (typeof window.soonConsumeOpenMeta === 'function') {
window.soonConsumeOpenMeta(file);
}
var p = window.openFile(file)
if (p && p.then) p.then(function() {}, function() {})
window.openFile(file);
}
});
});
+33 -8
View File
@@ -401,6 +401,7 @@ window.display_func = function display_func(img1, img2, img3) {
layer.open({
type: 1,
skin: 'soon-layer',
area: [w, h],
title: language_str("display"), //不显示标题栏"预览"
shadeClose: true, //点击遮罩关闭
@@ -1097,8 +1098,14 @@ window.openFile = function open(file, jAlready) {
if (!file) return;
if (typeof window.soonBindFileMeta === 'function') window.soonBindFileMeta(file);
function doOpenWithJson(j) {
if (!j || !background_image) return;
if (!j.f || !j.f.objects || !Array.isArray(j.f.objects) || j.f.objects.length === 0) return;
if (!j || !background_image) {
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
return;
}
if (!j.f || !j.f.objects || !Array.isArray(j.f.objects) || j.f.objects.length === 0) {
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' };
}
@@ -1173,12 +1180,14 @@ window.openFile = function open(file, jAlready) {
var j2 = canvas2.toJSON(props);
recordJson2.push(j2);
}, 0);
if (typeof window.soonTryConsumeCloudImport === 'function') window.soonTryConsumeCloudImport(file);
}
});
}
if (arguments.length >= 2 && jAlready) {
doOpenWithJson(jAlready);
openAs.name = file;
if (typeof window.soonTryConsumeCloudImport === 'function') window.soonTryConsumeCloudImport(file);
return;
}
if (window.platformBridge && window.platformBridge.readJsonFile) {
@@ -1186,8 +1195,12 @@ window.openFile = function open(file, jAlready) {
if (j) {
doOpenWithJson(j);
openAs.name = file;
} else if (typeof window.soonReportOpenLoadError === 'function') {
window.soonReportOpenLoadError('模板/文件加载失败');
}
}).catch(function() {});
}).catch(function () {
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
});
}
try {
var fs = typeof require !== 'undefined' ? require('fs') : null;
@@ -1252,6 +1265,9 @@ function cloudSaveSuccessLabel(res, fallback) {
function onCloudWriteDone(res, fallback, callback) {
applyCloudWriteResult(res, fallback);
if (res && res.fileKey && typeof window.soonClearPendingImport === 'function') {
window.soonClearPendingImport();
}
layer.msg(language_str("saveSucc") + cloudSaveSuccessLabel(res, fallback));
if (callback && typeof callback === 'function') callback();
}
@@ -1260,6 +1276,15 @@ function guardWebSave() {
return typeof window.soonGuardCloudSave === 'function' ? window.soonGuardCloudSave() : true;
}
function reportSaveError(err) {
if (err && err.status) return;
if (typeof window.soonShowApiError === 'function') {
window.soonShowApiError({ status: err && err.status, message: (err && err.message) || '保存失败' });
} else if (typeof window.soonToast === 'function') {
window.soonToast('保存失败', 'error');
}
}
function saveAs(op1, callback) {
// 临时移除辅助线,保存后再恢复
let guideLines1 = [];
@@ -1311,7 +1336,7 @@ function saveAs(op1, callback) {
if (window.platformBridge && window.platformBridge.writeFile) {
window.platformBridge.writeFile(fp, content).then(function (res) {
onCloudWriteDone(res, fp, callback);
}).catch(function () {});
}).catch(reportSaveError);
return;
}
var fs = typeof require !== 'undefined' ? require('fs') : null;
@@ -1322,7 +1347,7 @@ function saveAs(op1, callback) {
saveHistory();
if (callback && typeof callback === 'function') callback();
}
}).catch(function(err) {});
}).catch(reportSaveError);
}
function save(op1, callback) {
@@ -1365,7 +1390,7 @@ function save(op1, callback) {
if (window.platformBridge && window.platformBridge.writeFile) {
window.platformBridge.writeFile(openAs.name, content).then(function (res) {
onCloudWriteDone(res, openAs.name, callback);
}).catch(function () {});
}).catch(reportSaveError);
return;
}
var fs = typeof require !== 'undefined' ? require('fs') : null;
@@ -1394,7 +1419,7 @@ function save(op1, callback) {
if (window.platformBridge && window.platformBridge.writeFile) {
window.platformBridge.writeFile(fp, content).then(function (res) {
onCloudWriteDone(res, fp, callback);
}).catch(function () {});
}).catch(reportSaveError);
return;
}
var fs = typeof require !== 'undefined' ? require('fs') : null;
@@ -1405,7 +1430,7 @@ function save(op1, callback) {
saveHistory();
if (callback && typeof callback === 'function') callback();
}
}).catch(function(err) {});
}).catch(reportSaveError);
}
window.saveHistory = function saveHistory() {
+8 -12
View File
@@ -1345,7 +1345,7 @@ $("#open").click(function () {
OpenDialog();
return;
}
layer.confirm('<font style="color:black">' + language_str("whetherSave") + '</font>', function (index) {//confirm 是否保存当前文件?
layer.confirm(language_str("whetherSave"), function (index) {//confirm 是否保存当前文件?
if (typeof window.output === 'function') {
window.output(OpenDialog);
}
@@ -1375,18 +1375,14 @@ $("#open").click(function () {
}
}
function importAndOpen(j, fileName) {
var tok = typeof window.soonGetAccessToken === 'function'
? window.soonGetAccessToken()
: (localStorage.getItem('soon_access') || '');
if (!tok && typeof window.soonPutSoonSession === 'function') {
if (typeof window.soonPutSoonSession === 'function') {
var localKey = window.soonPutSoonSession(j, fileName || 'design.soon');
if (localKey) openWithKey(localKey, j);
return;
if (!localKey) return;
if (typeof window.soonScheduleCloudImport === 'function') {
window.soonScheduleCloudImport(localKey, fileName || 'design.soon');
}
openWithKey(localKey, j);
}
if (!window.platformBridge || !window.platformBridge.importSoonFile) return;
window.platformBridge.importSoonFile(fileName || 'design.soon', j).then(function(res) {
if (res && res.fileKey) openWithKey(res.fileKey, j);
}).catch(function () {});
}
if (file && file.text) {
file.text().then(function(t) {
@@ -1445,7 +1441,7 @@ $("#new").click(function () {
else if (window.platformBridge) window.platformBridge.openFirstPage();
return;
}
layer.confirm('<font style="color:black">' + language_str("whetherSave") + '</font>', function (index) {//confirm 是否保存当前文件?
layer.confirm(language_str("whetherSave"), function (index) {//confirm 是否保存当前文件?
if (typeof window.output === 'function') {
window.output(function() { if (ipcRenderer) ipcRenderer.send('open-first-page'); else if (window.platformBridge) window.platformBridge.openFirstPage(); });
}
+73 -34
View File
@@ -2,15 +2,40 @@
// 注意:此代码在layui.use回调函数内部执行
// 全局变量已在主入口文件中定义,这里只需要初始化
$('#canvas1').attr('height', document.body.clientHeight - 100)
$('#canvas2').attr('height', document.body.clientHeight - 100)
$('#object_attribute').css('height', '470px')
$('#obj_list').css('height', document.body.clientHeight - 520)
$('.obj_list').css('height', $('#obj_list').height() - 32)
function soonDesign2MainHeight() {
var main = document.querySelector('.layui-fluid.main');
if (main && main.clientHeight > 40) return main.clientHeight;
var tb = document.getElementById('portal-topbar');
return Math.max(480, window.innerHeight - (tb ? tb.offsetHeight : 0));
}
$('.main').show()
$('#canvas1').attr('width', $('#canvas-div').width())
$('#canvas2').attr('width', $('#canvas-div').width())
function soonDesign2CanvasWidth() {
var w = $('#canvas-div').width();
if (w > 0) return w;
w = $('.col-left').width();
if (w > 0) return Math.max(320, w - 70);
return Math.max(320, window.innerWidth - 390);
}
function layoutDesign2Shell() {
var isWeb = !!(window.SOON_DEPLOY_CONFIG);
var mainH = soonDesign2MainHeight();
var canvasW = soonDesign2CanvasWidth();
var canvasH = isWeb ? Math.max(400, mainH - 130) : (document.body.clientHeight - 100);
$('#canvas1').attr('width', canvasW).attr('height', canvasH);
$('#canvas2').attr('width', canvasW).attr('height', canvasH);
if (!isWeb) {
$('#object_attribute').css('height', '470px');
$('#obj_list').css('height', Math.max(120, mainH - 520));
$('.obj_list').css('height', Math.max(80, $('#obj_list').height() - 32));
}
return { canvasW: canvasW, canvasH: canvasH };
}
var mainEl = document.querySelector('.layui-fluid.main');
if (mainEl) mainEl.style.display = 'flex';
else $('.main').show();
var _design2Layout = layoutDesign2Shell();
// 初始化Canvas对象
// 优化性能:在创建 Fabric Canvas 之前,先设置 canvas context 的 willReadFrequently
@@ -42,11 +67,19 @@ is_bgi_add = false
window.ctx1 = ctx1;
window.ctx2 = ctx2;
window.is_bgi_add = is_bgi_add;
canvas1.zoomToPoint(new fabric.Point(canvas1.width / 2, canvas1.height / 2), $('#canvas-div').width() / 1200 > 1 ? 1 : $('#canvas-div').width() / 1200)
//console.log(canvas1.width / 2, canvas1.height / 2);
//console.log($("#canvas-div").width() / 1200 > 1 ? 1 : $("#canvas-div").width() / 1200);
canvas2.zoomToPoint(new fabric.Point(canvas2.width / 2, canvas2.height / 2), $('#canvas-div').width() / 1200 > 1 ? 1 : $('#canvas-div').width() / 1200)
zoom = $('#canvas-div').width() / 1200 > 1 ? 1 : $('#canvas-div').width() / 1200
canvas1.zoomToPoint(new fabric.Point(canvas1.width / 2, canvas1.height / 2), (function () {
var divW = $('#canvas-div').width() || _design2Layout.canvasW || 800;
return divW / 1200 > 1 ? 1 : divW / 1200;
})())
canvas2.zoomToPoint(new fabric.Point(canvas2.width / 2, canvas2.height / 2), (function () {
var divW = $('#canvas-div').width() || _design2Layout.canvasW || 800;
return divW / 1200 > 1 ? 1 : divW / 1200;
})())
zoom = (function () {
var divW = $('#canvas-div').width() || _design2Layout.canvasW || 800;
var z = divW / 1200 > 1 ? 1 : divW / 1200;
return z > 0 ? z : 0.5;
})()
// 初始化标尺
function initRulers() {
@@ -486,6 +519,26 @@ function initRulers() {
}
initRulers();
if (window.SOON_DEPLOY_CONFIG && ($('#canvas-div').width() || 0) < 100) {
requestAnimationFrame(function () {
requestAnimationFrame(function () {
var layout = layoutDesign2Shell();
var divW = layout.canvasW;
zoom = divW / 1200 > 1 ? 1 : divW / 1200;
if (zoom <= 0) zoom = 0.5;
canvas1.setWidth(layout.canvasW);
canvas1.setHeight(layout.canvasH);
canvas2.setWidth(layout.canvasW);
canvas2.setHeight(layout.canvasH);
canvas1.zoomToPoint(new fabric.Point(canvas1.width / 2, canvas1.height / 2), zoom);
canvas2.zoomToPoint(new fabric.Point(canvas2.width / 2, canvas2.height / 2), zoom);
window.zoom = zoom;
canvas1.renderAll();
canvas2.renderAll();
initRulers();
});
});
}
$('#source_front').width(zoom * $('#source_front').width())
$('#source_back').width(zoom * $('#source_back').width())
$('.canvas-container:eq(1)').hide()
@@ -1629,28 +1682,14 @@ function addBackground() {
recordObjs2.push(JSON.stringify(objs2))
recordJson2.push(canvas2.toJSON(TO_JSON_PROPERTIES))
let file = GetFile().get('file');
if (!file && typeof sessionStorage !== 'undefined') {
try {
file = sessionStorage.getItem('soondesign_open_file');
if (file) {
sessionStorage.removeItem('soondesign_open_file');
sessionStorage.removeItem('soondesign_open_type');
}
} catch (e) {}
}
var file = typeof window.soonResolveOpenFileKey === 'function'
? window.soonResolveOpenFileKey(GetFile)
: (GetFile().get('file') || '');
if (file && file != 'empty') {
if (file.indexOf('soondesign_file:') === 0 && typeof sessionStorage !== 'undefined') {
try {
var metaRaw = sessionStorage.getItem('soondesign_open_meta');
if (metaRaw) {
window._soonFileMeta = JSON.parse(metaRaw);
sessionStorage.removeItem('soondesign_open_meta');
}
} catch (e) {}
if (typeof window.soonConsumeOpenMeta === 'function') {
window.soonConsumeOpenMeta(file);
}
var p = window.openFile(file);
if (p && p.then) p.then(function() {}, function() {});
window.openFile(file);
}
})
})
@@ -2048,7 +2087,7 @@ if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
}
function onCloseConfirm() {
layer.confirm(
'<font style="color:black">' + language_str('whetherSave') + '</font>',
language_str('whetherSave'),
{
btn: [language_str('save'), language_str('noSave'), language_str('cancel')],
btn3: function (index, layero) { }
+27 -6
View File
@@ -333,6 +333,7 @@ window.display_func = function display_func(img1, img2, img3) {
layer.open({
type: 1,
skin: 'soon-layer',
area: [w, h],
title: language_str('display'), //不显示标题栏"预览"
shadeClose: true, //点击遮罩关闭
@@ -1087,6 +1088,9 @@ function cloudSaveSuccessLabel(res, fallback) {
function onCloudWriteDone(res, fallback, callback) {
applyCloudWriteResult(res, fallback);
if (res && res.fileKey && typeof window.soonClearPendingImport === 'function') {
window.soonClearPendingImport();
}
layer.msg(language_str('saveSucc') + cloudSaveSuccessLabel(res, fallback));
if (callback && typeof callback === 'function') callback();
}
@@ -1095,6 +1099,15 @@ function guardWebSave() {
return typeof window.soonGuardCloudSave === 'function' ? window.soonGuardCloudSave() : true;
}
function reportSaveError(err) {
if (err && err.status) return;
if (typeof window.soonShowApiError === 'function') {
window.soonShowApiError({ status: err && err.status, message: (err && err.message) || '保存失败' });
} else if (typeof window.soonToast === 'function') {
window.soonToast('保存失败', 'error');
}
}
function saveAs(op1, callback) {
// 临时移除辅助线,保存后再恢复
let guideLines1 = []
@@ -1143,7 +1156,7 @@ function saveAs(op1, callback) {
if (window.platformBridge && window.platformBridge.writeFile) {
window.platformBridge.writeFile(fp, content).then(function (res) {
onCloudWriteDone(res, fp, callback);
}).catch(function () {});
}).catch(reportSaveError);
return;
}
var fs = typeof require !== 'undefined' ? require('fs') : null;
@@ -1155,7 +1168,7 @@ function saveAs(op1, callback) {
if (callback && typeof callback === 'function') callback();
}
})
.catch(function(err) {});
.catch(reportSaveError);
}
function save(op1, callback) {
@@ -1198,7 +1211,7 @@ function save(op1, callback) {
if (window.platformBridge && window.platformBridge.writeFile) {
window.platformBridge.writeFile(openAs.name, content).then(function (res) {
onCloudWriteDone(res, openAs.name, callback);
}).catch(function () {});
}).catch(reportSaveError);
return;
}
var fs = typeof require !== 'undefined' ? require('fs') : null;
@@ -1222,7 +1235,7 @@ function save(op1, callback) {
if (window.platformBridge && window.platformBridge.writeFile) {
window.platformBridge.writeFile(fp, content).then(function (res) {
onCloudWriteDone(res, fp, callback);
}).catch(function () {});
}).catch(reportSaveError);
return;
}
var fs = typeof require !== 'undefined' ? require('fs') : null;
@@ -1234,7 +1247,7 @@ function save(op1, callback) {
if (callback && typeof callback === 'function') callback();
}
})
.catch(function(err) {});
.catch(reportSaveError);
}
window.saveHistory = function saveHistory() {
@@ -1287,7 +1300,10 @@ window.openFile = function open(file, jAlready) {
if (!file) return;
if (typeof window.soonBindFileMeta === 'function') window.soonBindFileMeta(file);
function doOpenWithJson(j) {
if (!j || !background_image) return;
if (!j || !background_image) {
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
return;
}
openAs.name = file;
var left = background_image.left
let top = background_image.top
@@ -1438,6 +1454,7 @@ window.openFile = function open(file, jAlready) {
recordJson = recordJson2
step = step2
}
if (typeof window.soonTryConsumeCloudImport === 'function') window.soonTryConsumeCloudImport(file);
}
canvas1.loadFromJSON(j.f, function () {
@@ -1482,7 +1499,11 @@ window.openFile = function open(file, jAlready) {
if (j) {
doOpenWithJson(j);
openAs.name = file;
} else if (typeof window.soonReportOpenLoadError === 'function') {
window.soonReportOpenLoadError('模板/文件加载失败');
}
}).catch(function () {
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
});
}
try {
+8 -12
View File
@@ -1299,7 +1299,7 @@ $('#open').click(function () {
return;
}
layer.confirm(
'<font style="color:black">' + language_str('whetherSave') + '</font>',
language_str('whetherSave'),
function (index) {
if (typeof window.output === 'function') {
window.output(OpenDialog);
@@ -1326,18 +1326,14 @@ $('#open').click(function () {
if (typeof window.openFile === 'function') window.openFile(fileKey, j);
}
function importAndOpen(j, fileName) {
var tok = typeof window.soonGetAccessToken === 'function'
? window.soonGetAccessToken()
: (localStorage.getItem('soon_access') || '');
if (!tok && typeof window.soonPutSoonSession === 'function') {
if (typeof window.soonPutSoonSession === 'function') {
var localKey = window.soonPutSoonSession(j, fileName || 'design.soon');
if (localKey) openWithKey(localKey, j);
return;
if (!localKey) return;
if (typeof window.soonScheduleCloudImport === 'function') {
window.soonScheduleCloudImport(localKey, fileName || 'design.soon');
}
openWithKey(localKey, j);
}
if (!window.platformBridge || !window.platformBridge.importSoonFile) return;
window.platformBridge.importSoonFile(fileName || 'design.soon', j).then(function(res) {
if (res && res.fileKey) openWithKey(res.fileKey, j);
}).catch(function () {});
}
if (file && file.text) {
file.text().then(function(t) {
@@ -1364,7 +1360,7 @@ $('#new').click(function () {
return;
}
layer.confirm(
'<font style="color:black">' + language_str('whetherSave') + '</font>',
language_str('whetherSave'),
function (index) {
if (typeof window.output === 'function') {
window.output(goFirstPage);
+26 -49
View File
@@ -512,41 +512,26 @@ layui.use(['layer', 'form', 'jquery'], function () {
function resolveTemplateItem(m, base) {
var type = Number(m.type) || 1;
var id = m.id;
var v = m.updated_at ? ('?v=' + encodeURIComponent(m.updated_at)) : '';
return {
id: id,
name: m.name || m.title || '模板',
type: type,
thumbSrc: id ? (base + '/templates/' + id + '/thumb') : templateFallbackThumb(type),
file_url: id ? (base + '/templates/' + id + '/file') : (m.file_url || '')
thumbSrc: id ? (base + '/templates/' + id + '/thumb' + v) : templateFallbackThumb(type)
};
}
function openTemplateItem(m) {
var type = Number(m.type) || 1;
function openWithJson(j) {
if (!j) {
openDesign(type, '');
return;
}
var key = 'soondesign_session:tpl-' + Date.now();
try {
sessionStorage.setItem(key, JSON.stringify(j));
openDesign(type, key);
} catch (e) {
openDesign(type, '');
}
}
var fileUrl = m.file_url || '';
if (!fileUrl) {
openDesign(type, '');
var id = m && m.id;
if (!id) {
if (typeof window.soonToast === 'function') window.soonToast('模板不可用', 'error');
return;
}
fetch(fileUrl).then(function (r) {
if (!r.ok) throw new Error('fetch');
return r.json();
}).then(openWithJson).catch(function () {
openDesign(type, '');
});
var templateKey = typeof window.soonMakeTemplateKey === 'function'
? window.soonMakeTemplateKey(id)
: ('soondesign_template:' + id);
openDesign(type, templateKey);
}
function templateCardHtml(m, itemIndex) {
@@ -614,7 +599,9 @@ layui.use(['layer', 'form', 'jquery'], function () {
renderTemplatePager();
}
async function loadTemplates() {
var _templatesLoadedAt = 0;
async function loadTemplates(force) {
var grid = document.getElementById('templatesGrid');
@@ -622,6 +609,10 @@ layui.use(['layer', 'form', 'jquery'], function () {
if (!grid) return;
if (!force && _templatesLoadedAt && (Date.now() - _templatesLoadedAt) < 60000) {
return;
}
var base = (window.SOON_DEPLOY_CONFIG && window.SOON_DEPLOY_CONFIG.api_v1_base) || '';
if (!base) {
@@ -655,6 +646,7 @@ layui.use(['layer', 'form', 'jquery'], function () {
templateListState.total = templateListState.items.length;
templateListState.page = 1;
renderTemplatesPage();
_templatesLoadedAt = Date.now();
} catch (e) {
@@ -670,6 +662,14 @@ layui.use(['layer', 'form', 'jquery'], function () {
loadTemplates();
window.soonReloadTemplates = function () { loadTemplates(true); };
document.addEventListener('visibilitychange', function () {
if (document.visibilityState === 'visible') loadTemplates(false);
});
window.addEventListener('pageshow', function (e) {
if (e.persisted) loadTemplates(false);
});
var templatePrevNav = document.getElementById('templatePrev');
var templateNextNav = document.getElementById('templateNext');
if (templatePrevNav) {
@@ -879,30 +879,7 @@ layui.use(['layer', 'form', 'jquery'], function () {
}
var tok = typeof window.soonGetAccessToken === 'function'
? window.soonGetAccessToken()
: (localStorage.getItem('soon_access') || '');
if (!tok && typeof window.soonOpenSoonJsonLocally === 'function') {
window.soonOpenSoonJsonLocally(soonData, fileName);
return;
}
if (!window.platformBridge || !window.platformBridge.importSoonFile) return;
try {
var res = await window.platformBridge.importSoonFile(fileName, soonData);
if (!res || !res.fileKey) return;
var type = soonData.soonType ? soonData.soonType : (soonData.backBlackPic ? 2 : 1);
openDesign(type, res.fileKey);
loadHistory();
} catch (err) { /* errors shown by bridge */ }
window.soonOpenSoonJsonLocally(soonData, fileName);
}).catch(function (err) { console.log(err); });
+83 -20
View File
@@ -244,12 +244,46 @@
if (key && key.indexOf('soondesign_file:') === 0 && typeof fetch !== 'undefined') {
var fileMatch = key.match(/^soondesign_file:(\d+)/);
if (fileMatch && getAccessToken()) {
return authedFetch('files/' + fileMatch[1] + '/download', { headers: { Accept: 'application/json' } })
return authedFetch('files/' + fileMatch[1], { headers: { Accept: 'application/json' } })
.then(function (response) {
if (!response.ok) return null;
return response.text().then(function (text) {
try { return JSON.parse(text); } catch (e) { return null; }
});
return response.json();
})
.then(function (payload) {
if (!payload || !payload.ok || !payload.data) return null;
var raw = payload.data.json;
if (typeof raw === 'string') {
try { return JSON.parse(raw); } catch (e) { return null; }
}
return raw && typeof raw === 'object' ? raw : null;
})
.catch(function () { return null; });
}
}
if (key && key.indexOf('soondesign_template:') === 0 && typeof fetch !== 'undefined') {
var tplMatch = key.match(/^soondesign_template:(\d+)/);
if (tplMatch) {
var apiBase = (window.SOON_DEPLOY_CONFIG && window.SOON_DEPLOY_CONFIG.api_v1_base) || '';
if (!apiBase) return Promise.resolve(null);
return fetch(apiBase + '/templates/' + tplMatch[1], { headers: { Accept: 'application/json' } })
.then(function (response) {
if (!response.ok) return null;
return response.json();
})
.then(function (payload) {
if (!payload || !payload.ok || !payload.data) return null;
if (payload.data.id) {
window._soonTemplateMeta = {
id: payload.data.id,
name: payload.data.name || '',
type: payload.data.type
};
}
var raw = payload.data.json;
if (typeof raw === 'string') {
try { return JSON.parse(raw); } catch (e) { return null; }
}
return raw && typeof raw === 'object' ? raw : null;
})
.catch(function () { return null; });
}
@@ -294,18 +328,51 @@
showSaveDialog: function (options) {
var raw = (options && options.defaultPath) ? options.defaultPath : '';
var defaultName = normalizeSoonName(raw || 'design.soon');
if (typeof window.soonDisplayFileName === 'function' && raw.indexOf('soondesign_file:') === 0) {
if (typeof window.soonDisplayFileName === 'function' &&
(raw.indexOf('soondesign_file:') === 0 || raw.indexOf('soondesign_template:') === 0)) {
defaultName = window.soonDisplayFileName(raw);
}
var title = (options && options.title) ? options.title : '保存到云端';
return new Promise(function (resolve) {
var name = typeof prompt === 'function' ? prompt('保存为文件名(如 xxx.soon', defaultName) : defaultName;
if (name === null) {
resolve({ canceled: true });
if (typeof layer === 'undefined' || !layer.open) {
var fpFallback = defaultName;
resolve({ canceled: false, filePath: fpFallback, useCloud: true });
return;
}
var fp = (name && String(name).trim()) ? String(name).trim() : defaultName;
fp = normalizeSoonName(fp);
resolve({ canceled: false, filePath: fp, useCloud: true });
var esc = function (s) {
return String(s || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
};
var html = '<div class="soon-dialog-body" style="padding:16px 20px;">' +
'<label style="display:block;margin-bottom:8px;color:#b8c0c8;font-size:13px;">文件名</label>' +
'<input type="text" id="soonSaveDialogInput" class="layui-input" value="' + esc(defaultName) + '" ' +
'style="background:#2b3036;border-color:rgba(255,255,255,0.08);color:#eef1f4;">' +
'</div>';
layer.open({
type: 1,
skin: 'soon-layer',
title: title,
area: ['360px', 'auto'],
shadeClose: false,
content: html,
btn: ['确定', '取消'],
btnAlign: 'r',
yes: function (index) {
var input = document.getElementById('soonSaveDialogInput');
var name = input && input.value ? String(input.value).trim() : defaultName;
if (!name) name = defaultName;
name = normalizeSoonName(name);
layer.close(index);
resolve({ canceled: false, filePath: name, useCloud: true });
},
btn2: function (index) {
layer.close(index);
resolve({ canceled: true });
},
cancel: function (index) {
layer.close(index);
resolve({ canceled: true });
}
});
});
},
writeFile: function (pathOrHandle, content) {
@@ -383,16 +450,11 @@
getSystemFonts: getSystemFonts,
openDesignPage: function (file, type) {
var t = type || 1;
if (file && typeof sessionStorage !== 'undefined') {
try {
sessionStorage.setItem('soondesign_open_file', file);
sessionStorage.setItem('soondesign_open_type', String(t));
if (file.indexOf('soondesign_file:') === 0 && window._soonFileMeta) {
sessionStorage.setItem('soondesign_open_meta', JSON.stringify(window._soonFileMeta));
}
} catch (e) {}
var key = file || '';
if (typeof window.soonSyncOpenNavigation === 'function') {
window.soonSyncOpenNavigation(key, t);
}
var fileParam = file ? encodeURIComponent(file) : '';
var fileParam = key ? encodeURIComponent(key) : '';
navigateToPage('design' + t + '.web.html?file=' + fileParam + '&type=' + t);
},
openFirstPage: function () {
@@ -453,6 +515,7 @@
showOpenDialog: bridge.showOpenDialog,
showSaveDialog: bridge.showSaveDialog
};
window.soonShowSaveDialog = bridge.showSaveDialog;
window.path = pathStub;
window.fs = null;
window.remote = null;