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
+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;