网页端:平台桥与部署修复(宝塔/Nginx)
- lib/platform:网页 Electron 统一 bridge/web/electron,子目录 API 基路径、返回首页跳站点根、路径末尾斜杠兼容 - index/design*.web.html:网页入口,web.js 加缓存参数避免旧脚本缓存 - api:PHP 读写 soon;文档说明目录权限与 Nginx - lib/design*、lib/index:与 platformBridge 对接及网页侧逻辑 - 公共资源 JsBarcode/jr-qrcode;文档与 package/README/.gitignore 等同步更新 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+47
-21
@@ -81,25 +81,31 @@ canvas2.preserveObjectStacking = true;
|
||||
|
||||
|
||||
var front_list = [];
|
||||
ipcRenderer.on('font-list', (event, data) => {
|
||||
const newFontList = [];
|
||||
data.map(item => {
|
||||
function applyFontList(data) {
|
||||
var newFontList = [];
|
||||
(data || []).map(function(item) {
|
||||
if (item.indexOf('"') === 0) {
|
||||
newFontList.push(item.replace(/^"|"$/g, ''));
|
||||
} else {
|
||||
newFontList.push(item);
|
||||
}
|
||||
})
|
||||
});
|
||||
front_list = newFontList;
|
||||
for (let item of front_list) {
|
||||
for (var i = 0; i < front_list.length; i++) {
|
||||
var item = front_list[i];
|
||||
$("#text_font_family").append("<option value='" + item + "'>" + item + "</option>");
|
||||
$("#circle_text_font_family").append("<option value='" + item + "'>" + item + "</option>");
|
||||
$("#out_text_font_family").append("<option value='" + item + "'>" + item + "</option>");
|
||||
$("#barcode_font_family").append("<option value='" + item + "'>" + item + "</option>");
|
||||
$("#count_font_family").append("<option value='" + item + "'>" + item + "</option>");
|
||||
}
|
||||
});
|
||||
ipcRenderer.on('sys-lan', (event, data) => {
|
||||
}
|
||||
if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
|
||||
ipcRenderer.on('font-list', function(event, data) { applyFontList(data); });
|
||||
} else if (typeof window !== 'undefined' && window.platformBridge && window.platformBridge.getSystemFonts) {
|
||||
window.platformBridge.getSystemFonts().then(applyFontList);
|
||||
}
|
||||
function applySysLan(data) {
|
||||
let lang = localStorage.getItem("lang");
|
||||
if (lang) {
|
||||
s_lan = lang;
|
||||
@@ -246,23 +252,33 @@ ipcRenderer.on('sys-lan', (event, data) => {
|
||||
localStorage.setItem("lang", "en");
|
||||
break;
|
||||
}
|
||||
});
|
||||
ipcRenderer.on('close', (event, message) => {
|
||||
layer.confirm('<font style="color:black">' + language_str("whetherSave") + '</font>', {//是否保存当前文件?
|
||||
btn: [language_str("save"), language_str("noSave"), language_str("cancel")] //['保存', '不保存', '取消']
|
||||
, btn3: function (index, layero) {
|
||||
|
||||
}
|
||||
}
|
||||
if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
|
||||
ipcRenderer.on('sys-lan', function(event, data) { applySysLan(data); });
|
||||
} else if (typeof window !== 'undefined' && window.platformBridge && window.platformBridge.getLocale) {
|
||||
applySysLan(window.platformBridge.getLocale());
|
||||
}
|
||||
function onCloseConfirm() {
|
||||
layer.confirm('<font style="color:black">' + language_str("whetherSave") + '</font>', {
|
||||
btn: [language_str("save"), language_str("noSave"), language_str("cancel")]
|
||||
, btn3: function (index, layero) {}
|
||||
}, function (index, layero) {
|
||||
|
||||
if (typeof window.output === 'function') {
|
||||
window.output(() => ipcRenderer.send('run-close'));
|
||||
window.output(function() {
|
||||
if (ipcRenderer) ipcRenderer.send('run-close');
|
||||
else if (window.platformBridge && window.platformBridge.runClose) window.platformBridge.runClose();
|
||||
});
|
||||
}
|
||||
}, function (index) {
|
||||
ipcRenderer.send('run-close');
|
||||
if (ipcRenderer) ipcRenderer.send('run-close');
|
||||
else if (window.platformBridge && window.platformBridge.runClose) window.platformBridge.runClose();
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
|
||||
ipcRenderer.on('close', function(event, message) { onCloseConfirm(); });
|
||||
} else if (typeof window !== 'undefined' && window.platformBridge && window.platformBridge.onClose) {
|
||||
window.platformBridge.onClose(onCloseConfirm);
|
||||
}
|
||||
addBackground();//添加背景 白色卡片
|
||||
initAligningGuidelines(canvas1);
|
||||
initAligningGuidelines(canvas2);
|
||||
@@ -402,9 +418,19 @@ function addBackground() {
|
||||
recordObjs2.push(JSON.stringify(objs2));
|
||||
recordJson2.push(canvas2.toJSON(TO_JSON_PROPERTIES));
|
||||
|
||||
let file = GetFile().get('file')
|
||||
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) {}
|
||||
}
|
||||
if (file && file != 'empty') {
|
||||
window.openFile(file)
|
||||
var p = window.openFile(file)
|
||||
if (p && p.then) p.then(function() {}, function() {})
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
+279
-266
@@ -14,27 +14,41 @@ var openAs = {
|
||||
}
|
||||
};
|
||||
|
||||
// 导出文件
|
||||
// 导出文件(兼容桌面 fs 与网页 bridge 下载)
|
||||
async function saveImageAsPNG(buffer) {
|
||||
let fs = require('fs');
|
||||
// 弹出保存对话框
|
||||
const { canceled, filePath } = await dialog.showSaveDialog({
|
||||
var dialogApi = (typeof dialog !== 'undefined' && dialog) ? dialog : (window.platformBridge && window.platformBridge.showSaveDialog ? { showSaveDialog: function(opts) { return window.platformBridge.showSaveDialog(opts); } } : null);
|
||||
if (!dialogApi) return;
|
||||
var pathJoin = (path && path.join) ? path.join.bind(path) : function() { return [].slice.call(arguments).join('/').replace(/\/+/g, '/'); };
|
||||
var defaultPath = exePath ? pathJoin(exePath, 'output.png') : 'output.png';
|
||||
const result = await dialogApi.showSaveDialog({
|
||||
title: '保存图片',
|
||||
defaultPath: path.join(exePath, 'output.png'), // 默认路径
|
||||
filters: [{ name: 'PNG Images', extensions: ['png'] }] // 文件过滤器
|
||||
defaultPath: defaultPath,
|
||||
filters: [{ name: 'PNG Images', extensions: ['png'] }]
|
||||
});
|
||||
|
||||
if (canceled) {
|
||||
var canceled = result.canceled, filePath = result.filePath || result.fileHandle;
|
||||
if (canceled || !filePath) return;
|
||||
if (window.platformBridge && window.platformBridge.writeFile) {
|
||||
var blob = buffer instanceof Uint8Array ? new Blob([buffer]) : (buffer && buffer.buffer ? new Blob([buffer]) : new Blob([buffer]));
|
||||
var name = (typeof filePath === 'string' ? filePath.split(/[/\\]/).pop() : 'output.png') || 'output.png';
|
||||
if (!/\.png$/i.test(name)) name = name + '.png';
|
||||
if (result.fileHandle && result.fileHandle.createWritable) {
|
||||
result.fileHandle.createWritable().then(function(w) { w.write(blob); return w.close(); }).then(function() { layer.msg(language_str("saveSucc") + name); });
|
||||
} else {
|
||||
var a = document.createElement('a');
|
||||
a.download = name;
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.click();
|
||||
URL.revokeObjectURL(a.href);
|
||||
layer.msg(language_str("saveSucc") + name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 将Buffer写入PNG文件到用户选择的路径
|
||||
fs.writeFile(filePath, buffer, (err) => {
|
||||
if (err) {
|
||||
} else {
|
||||
layer.msg(language_str("saveSucc") + filePath);//'保存成功至'
|
||||
}
|
||||
});
|
||||
var fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (fs) {
|
||||
fs.writeFile(filePath, buffer, (err) => {
|
||||
if (!err) layer.msg(language_str("saveSucc") + filePath);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 将 display_func 附加到 window 对象,确保全局可访问
|
||||
@@ -368,11 +382,22 @@ window.display_func = function display_func(img1, img2, img3) {
|
||||
w = ((document.body.clientHeight * 0.8 - 150) / 0.62548 + 40) / 0.94
|
||||
}
|
||||
|
||||
let fs = require('fs');
|
||||
const Buffer = require('buffer').Buffer;
|
||||
const buffer = Buffer.from(url3.replace(/^data:image\/\w+;base64,/, ""), 'base64');
|
||||
const printPath = path.join(exePath, 'print.png');
|
||||
fs.writeFileSync(printPath, buffer);
|
||||
var printPath, printBlobUrl, buffer;
|
||||
if (typeof require !== 'undefined' && require('fs')) {
|
||||
var fs = require('fs');
|
||||
var Buffer = require('buffer').Buffer;
|
||||
var buf = Buffer.from(url3.replace(/^data:image\/\w+;base64,/, ""), 'base64');
|
||||
printPath = path.join(exePath, 'print.png');
|
||||
fs.writeFileSync(printPath, buf);
|
||||
buffer = buf;
|
||||
} else {
|
||||
var bin = atob(url3.replace(/^data:image\/\w+;base64,/, ""));
|
||||
var arr = new Uint8Array(bin.length);
|
||||
for (var i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
|
||||
buffer = arr;
|
||||
printBlobUrl = URL.createObjectURL(new Blob([arr], { type: 'image/png' }));
|
||||
printPath = printBlobUrl;
|
||||
}
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
@@ -392,14 +417,18 @@ window.display_func = function display_func(img1, img2, img3) {
|
||||
</div>`,
|
||||
btn: [language_str("output"), "打印"],//'导出'
|
||||
btn1: function (index, layero) {
|
||||
// 只处理导出(保存PNG)
|
||||
saveImageAsPNG(buffer)
|
||||
saveImageAsPNG(buffer);
|
||||
},
|
||||
btn2: function () {
|
||||
// 只处理打印
|
||||
printJS({ printable: printPath, type: 'image', style: 'img { width: 100%; height: auto; }' })
|
||||
if (window.platformBridge && window.platformBridge.printPdf) {
|
||||
var blob = buffer instanceof Uint8Array ? new Blob([buffer], { type: 'image/png' }) : new Blob([buffer], { type: 'image/png' });
|
||||
window.platformBridge.printPdf(blob);
|
||||
} else if (typeof printJS === 'function') {
|
||||
printJS({ printable: printPath, type: 'image', style: 'img { width: 100%; height: auto; }' });
|
||||
}
|
||||
},
|
||||
end: function () {
|
||||
if (printBlobUrl) try { URL.revokeObjectURL(printBlobUrl); } catch (e) {}
|
||||
// 预览窗口关闭后,恢复所有对象的 selectable 和 evented 状态
|
||||
canvas1.getObjects().forEach((obj, index) => {
|
||||
if (!obj.isGuideLine && objStates1[index]) {
|
||||
@@ -1047,157 +1076,111 @@ window.regenerateQrCodesAndBarcodes = function regenerateQrCodesAndBarcodes(canv
|
||||
|
||||
// open() 函数在 output.js 中定义,因为 output.js 先于 core.js 加载
|
||||
// 使用 window.openFile 避免与浏览器原生的 window.open 冲突
|
||||
window.openFile = function open(file) {
|
||||
try {
|
||||
let fs = require('fs');
|
||||
if (!fs.existsSync(file)) {
|
||||
return;
|
||||
}
|
||||
var fsData = fs.readFileSync(file);
|
||||
openAs.name = file;
|
||||
let j;
|
||||
try {
|
||||
j = JSON.parse(fsData.toString());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!background_image) {
|
||||
return;
|
||||
}
|
||||
if (!j.f || !j.f.objects || !Array.isArray(j.f.objects) || j.f.objects.length === 0) {
|
||||
return;
|
||||
}
|
||||
window.openFile = function open(file, jAlready) {
|
||||
if (!file) return;
|
||||
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.b || !j.b.objects || !Array.isArray(j.b.objects) || j.b.objects.length === 0) {
|
||||
j.b = {
|
||||
version: '4.6.0',
|
||||
objects: [],
|
||||
hoverCursor: 'move'
|
||||
};
|
||||
j.b = { version: '4.6.0', objects: [], hoverCursor: 'move' };
|
||||
}
|
||||
|
||||
let left = background_image.left;
|
||||
let top = background_image.top;
|
||||
let new_left = j.f.objects[0].left;
|
||||
let new_top = j.f.objects[0].top;
|
||||
for (let o of j.f.objects) {
|
||||
o.left = o.left - new_left + left;
|
||||
o.top = o.top - new_top + top;
|
||||
openAs.name = file;
|
||||
var left = background_image.left;
|
||||
var top = background_image.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++) {
|
||||
j.f.objects[i].left = j.f.objects[i].left - new_left + left;
|
||||
j.f.objects[i].top = j.f.objects[i].top - new_top + top;
|
||||
}
|
||||
if (j.f.objects[0] && !j.f.objects[0].src) {
|
||||
j.f.objects[0].src = './public/images/bg_front_1.png'
|
||||
}
|
||||
if (j.b.objects && j.b.objects.length > 0 && j.b.objects[0] && !j.b.objects[0].src) {
|
||||
j.b.objects[0].src = './public/images/bg_back.png'
|
||||
}
|
||||
|
||||
const fo = j.fo || [];
|
||||
const bo = j.bo || [];
|
||||
const placeholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
||||
|
||||
fo.forEach((objMeta, idx) => {
|
||||
if ((objMeta.type === 8 || objMeta.type === 9) && j.f.objects[idx + 1] && !j.f.objects[idx + 1].src) {
|
||||
j.f.objects[idx + 1].src = placeholder;
|
||||
} else if (objMeta.type === 2 && j.f.objects[idx + 1] && !j.f.objects[idx + 1].src) {
|
||||
// 合成图片类型,恢复默认图片
|
||||
j.f.objects[idx + 1].src = './public/images/outpic_extra.png';
|
||||
}
|
||||
if (j.f.objects[0] && !j.f.objects[0].src) j.f.objects[0].src = './public/images/bg_front_1.png';
|
||||
if (j.b.objects && j.b.objects[0] && !j.b.objects[0].src) j.b.objects[0].src = './public/images/bg_back.png';
|
||||
var fo = j.fo || [], bo = j.bo || [];
|
||||
var placeholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
||||
fo.forEach(function(objMeta, idx) {
|
||||
if ((objMeta.type === 8 || objMeta.type === 9) && j.f.objects[idx + 1] && !j.f.objects[idx + 1].src) j.f.objects[idx + 1].src = placeholder;
|
||||
else if (objMeta.type === 2 && j.f.objects[idx + 1] && !j.f.objects[idx + 1].src) j.f.objects[idx + 1].src = './public/images/outpic_extra.png';
|
||||
});
|
||||
|
||||
bo.forEach((objMeta, idx) => {
|
||||
if ((objMeta.type === 8 || objMeta.type === 9) && j.b.objects && j.b.objects[idx + 1] && !j.b.objects[idx + 1].src) {
|
||||
j.b.objects[idx + 1].src = placeholder;
|
||||
} else if (objMeta.type === 2 && j.b.objects && j.b.objects[idx + 1] && !j.b.objects[idx + 1].src) {
|
||||
// 合成图片类型,恢复默认图片
|
||||
j.b.objects[idx + 1].src = './public/images/outpic_extra.png';
|
||||
}
|
||||
bo.forEach(function(objMeta, idx) {
|
||||
if ((objMeta.type === 8 || objMeta.type === 9) && j.b.objects && j.b.objects[idx + 1] && !j.b.objects[idx + 1].src) j.b.objects[idx + 1].src = placeholder;
|
||||
else if (objMeta.type === 2 && j.b.objects && j.b.objects[idx + 1] && !j.b.objects[idx + 1].src) j.b.objects[idx + 1].src = './public/images/outpic_extra.png';
|
||||
});
|
||||
|
||||
canvas1.loadFromJSON(j.f, function () {
|
||||
// 加载后解锁所有对象(背景除外)
|
||||
if (typeof window.unlockAllObjects === 'function') {
|
||||
window.unlockAllObjects(canvas1);
|
||||
}
|
||||
if (typeof window.regenerateQrCodesAndBarcodes === 'function') {
|
||||
window.regenerateQrCodesAndBarcodes(canvas1, fo);
|
||||
}
|
||||
// 加载后更新列表和图标显示
|
||||
if (typeof window.updateList === 'function') {
|
||||
window.updateList();
|
||||
}
|
||||
canvas1.loadFromJSON(j.f, function() {
|
||||
if (typeof window.unlockAllObjects === 'function') window.unlockAllObjects(canvas1);
|
||||
if (typeof window.regenerateQrCodesAndBarcodes === 'function') window.regenerateQrCodesAndBarcodes(canvas1, fo);
|
||||
if (typeof window.updateList === 'function') window.updateList();
|
||||
canvas1.renderAll();
|
||||
});
|
||||
canvas2.loadFromJSON(j.b, function () {
|
||||
// 加载后解锁所有对象(背景除外)
|
||||
if (typeof window.unlockAllObjects === 'function') {
|
||||
window.unlockAllObjects(canvas2);
|
||||
}
|
||||
if (typeof window.regenerateQrCodesAndBarcodes === 'function') {
|
||||
window.regenerateQrCodesAndBarcodes(canvas2, bo);
|
||||
}
|
||||
// 加载后更新列表和图标显示
|
||||
if (typeof window.updateList === 'function') {
|
||||
window.updateList();
|
||||
}
|
||||
canvas2.loadFromJSON(j.b, function() {
|
||||
if (typeof window.unlockAllObjects === 'function') window.unlockAllObjects(canvas2);
|
||||
if (typeof window.regenerateQrCodesAndBarcodes === 'function') window.regenerateQrCodesAndBarcodes(canvas2, bo);
|
||||
if (typeof window.updateList === 'function') window.updateList();
|
||||
canvas2.renderAll();
|
||||
});
|
||||
|
||||
let objects1 = canvas1.getObjects();
|
||||
let objects2 = canvas2.getObjects();
|
||||
if (!objects1 || objects1.length === 0) {
|
||||
return;
|
||||
}
|
||||
background_image1 = objects1[0];
|
||||
background_image2 = objects2 && objects2.length > 0 ? objects2[0] : null;
|
||||
|
||||
objs2 = j.bo || [];
|
||||
objs1 = j.fo || [];
|
||||
step1.val = 0;
|
||||
step2.val = 0;
|
||||
recordJson1 = [];
|
||||
recordJson2 = [];
|
||||
recordObjs1 = [];
|
||||
recordObjs2 = [];
|
||||
if ($("#front_side").hasClass("ui-button-active")) {
|
||||
objs = objs1;
|
||||
recordObjs = recordObjs1;
|
||||
recordJson = recordJson1;
|
||||
step = step1;
|
||||
background_image = background_image1;
|
||||
} else if ($("#back_side").hasClass("ui-button-active")) {
|
||||
objs = objs2;
|
||||
recordObjs = recordObjs2;
|
||||
recordJson = recordJson2;
|
||||
background_image = background_image2 || background_image1;
|
||||
step = step2;
|
||||
}
|
||||
canvas1.renderAll();
|
||||
canvas2.renderAll();
|
||||
// 调用 updateList,现在它已附加到 window 对象
|
||||
if (typeof window.updateList === 'function') {
|
||||
window.updateList();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
if (typeof window.updateList === 'function') {
|
||||
window.updateList();
|
||||
var objects1 = canvas1.getObjects(), objects2 = canvas2.getObjects();
|
||||
if (objects1 && objects1.length > 0) {
|
||||
background_image1 = objects1[0];
|
||||
background_image2 = objects2 && objects2.length > 0 ? objects2[0] : null;
|
||||
objs2 = j.bo || [];
|
||||
objs1 = j.fo || [];
|
||||
step1.val = 0;
|
||||
step2.val = 0;
|
||||
recordJson1 = [];
|
||||
recordJson2 = [];
|
||||
recordObjs1 = [];
|
||||
recordObjs2 = [];
|
||||
if ($("#front_side").hasClass("ui-button-active")) {
|
||||
objs = objs1;
|
||||
recordObjs = recordObjs1;
|
||||
recordJson = recordJson1;
|
||||
step = step1;
|
||||
background_image = background_image1;
|
||||
} else if ($("#back_side").hasClass("ui-button-active")) {
|
||||
objs = objs2;
|
||||
recordObjs = recordObjs2;
|
||||
recordJson = recordJson2;
|
||||
background_image = background_image2 || background_image1;
|
||||
step = step2;
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
setTimeout(() => {
|
||||
recordObjs1.push(JSON.stringify(objs1))
|
||||
const props = window.TO_JSON_PROPERTIES || ["selectable", "hoverable", "hoverCursor", "text", "fontStyle", "fontWeight", "underline", "evented"];
|
||||
let j1 = canvas1.toJSON(props);
|
||||
j1.objects[0].hoverCursor = "default";
|
||||
recordJson1.push(j1);
|
||||
|
||||
recordObjs2.push(JSON.stringify(objs2))
|
||||
let j2 = canvas2.toJSON(props);
|
||||
recordJson2.push(j2);
|
||||
}, 0);
|
||||
} catch (e) {
|
||||
// 静默处理错误
|
||||
canvas1.renderAll();
|
||||
canvas2.renderAll();
|
||||
if (typeof window.updateList === 'function') window.updateList();
|
||||
else setTimeout(function() { if (typeof window.updateList === 'function') window.updateList(); }, 100);
|
||||
setTimeout(function() {
|
||||
recordObjs1.push(JSON.stringify(objs1));
|
||||
var props = window.TO_JSON_PROPERTIES || ["selectable", "hoverable", "hoverCursor", "text", "fontStyle", "fontWeight", "underline", "evented"];
|
||||
var j1 = canvas1.toJSON(props);
|
||||
if (j1.objects && j1.objects[0]) j1.objects[0].hoverCursor = "default";
|
||||
recordJson1.push(j1);
|
||||
recordObjs2.push(JSON.stringify(objs2));
|
||||
var j2 = canvas2.toJSON(props);
|
||||
recordJson2.push(j2);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (arguments.length >= 2 && jAlready) {
|
||||
doOpenWithJson(jAlready);
|
||||
openAs.name = file;
|
||||
return;
|
||||
}
|
||||
if (window.platformBridge && window.platformBridge.readJsonFile) {
|
||||
return window.platformBridge.readJsonFile(file).then(function(j) {
|
||||
if (j) {
|
||||
doOpenWithJson(j);
|
||||
openAs.name = file;
|
||||
}
|
||||
}).catch(function() {});
|
||||
}
|
||||
try {
|
||||
var fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (!fs || file.indexOf('soondesign_session:') === 0) return;
|
||||
if (!fs.existsSync(file)) return;
|
||||
var fsData = fs.readFileSync(file);
|
||||
var j;
|
||||
try { j = JSON.parse(fsData.toString()); } catch (e) { return; }
|
||||
doOpenWithJson(j);
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
// 清理不需要的 src 字段(保留自定义图片的 src)
|
||||
// 将 cleanupSrcFields 附加到 window 对象,确保在 ui.js 中的 saveAs 函数也能访问
|
||||
@@ -1266,34 +1249,37 @@ function saveAs(op1, callback) {
|
||||
|
||||
let o = { f: j, b: {}, fo: objs1, bo: objs2 };
|
||||
let con_o = Object.assign(o, op1);
|
||||
dialog.showSaveDialog({
|
||||
title: language_str("saveFile"),//'保存文件'
|
||||
filters: [
|
||||
{ name: 'Soon File Type', extensions: ['soon'] },
|
||||
],
|
||||
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({
|
||||
title: language_str("saveFile"),
|
||||
filters: [{ name: 'Soon File Type', extensions: ['soon'] }],
|
||||
defaultPath: openAs.name || undefined
|
||||
}).then(result => {
|
||||
if (result.filePath == "") { return; }
|
||||
if (result.filePath == null || result.filePath == undefined) { return; }
|
||||
// 检查文件扩展名,确保以.soon结尾
|
||||
const path = require('path');
|
||||
let filePath = result.filePath;
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
if (ext !== '.soon') {
|
||||
filePath = filePath + '.soon';
|
||||
}).then(async function(result) {
|
||||
var fp = result.filePath || (result.fileHandle && result.fileHandle.name);
|
||||
if (!fp && !result.fileHandle) return;
|
||||
var pathExt = (typeof window !== 'undefined' && window.path && window.path.extname) ? window.path.extname(fp) : (fp.indexOf('.') >= 0 ? fp.slice(fp.lastIndexOf('.')) : '');
|
||||
if (pathExt !== '.soon') fp = (fp || 'design').replace(/\.soon$/i, '') + '.soon';
|
||||
var content = JSON.stringify(con_o);
|
||||
con_o.soonType = 1;
|
||||
if (window.platformBridge && window.platformBridge.writeFile) {
|
||||
await window.platformBridge.writeFile(result.fileHandle || fp, content);
|
||||
openAs.name = 'soondesign_session:' + fp;
|
||||
webSessionStore(content, fp);
|
||||
layer.msg(language_str("saveSucc") + fp);
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') callback();
|
||||
return;
|
||||
}
|
||||
result.filePath = filePath;
|
||||
let fs = require('fs')
|
||||
con_o.soonType = 1
|
||||
fs.writeFileSync(result.filePath, JSON.stringify(con_o), 'utf8')
|
||||
openAs.name = result.filePath;
|
||||
layer.msg(language_str("saveSucc") + openAs.name);//'保存成功至'
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback();
|
||||
var fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (fs) {
|
||||
fs.writeFileSync(result.filePath || fp, content, 'utf8');
|
||||
openAs.name = result.filePath || fp;
|
||||
layer.msg(language_str("saveSucc") + openAs.name);
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') callback();
|
||||
}
|
||||
}).catch(err => {
|
||||
})
|
||||
}).catch(function(err) {});
|
||||
}
|
||||
|
||||
function save(op1, callback) {
|
||||
@@ -1330,95 +1316,122 @@ function save(op1, callback) {
|
||||
let o = { f: j, b: {}, fo: objs1, bo: objs2 };
|
||||
let con_o = Object.assign(o, op1);
|
||||
if (openAs.name != "") {
|
||||
//打开的文件
|
||||
let fs = require('fs')
|
||||
con_o.soonType = 1
|
||||
fs.writeFileSync(openAs.name, JSON.stringify(con_o), 'utf8')
|
||||
layer.msg(language_str("saveSucc") + openAs.name);//'保存成功至'
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback();
|
||||
con_o.soonType = 1;
|
||||
var content = JSON.stringify(con_o);
|
||||
if (openAs.name.indexOf('soondesign_session:') === 0) {
|
||||
webSessionStore(content, openAs.name);
|
||||
// 服务器环境:同时保存到服务器
|
||||
var fileName = openAs.name.replace(/^soondesign_session:/, '');
|
||||
if (window.platformBridge && window.platformBridge.writeFile && fileName) {
|
||||
window.platformBridge.writeFile(fileName, content).catch(function() {});
|
||||
}
|
||||
layer.msg(language_str("saveSucc") + fileName);
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') callback();
|
||||
return;
|
||||
}
|
||||
if (window.platformBridge && window.platformBridge.writeFile) {
|
||||
webSessionStore(content, openAs.name);
|
||||
window.platformBridge.writeFile(openAs.name, content).then(function() {
|
||||
layer.msg(language_str("saveSucc") + openAs.name);
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') callback();
|
||||
});
|
||||
return;
|
||||
}
|
||||
var fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (fs) {
|
||||
fs.writeFileSync(openAs.name, content, 'utf8');
|
||||
layer.msg(language_str("saveSucc") + openAs.name);
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
dialog.showSaveDialog({
|
||||
title: language_str("saveFile"),//'保存文件'
|
||||
filters: [
|
||||
{ name: 'Soon File Type', extensions: ['soon'] },
|
||||
],
|
||||
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({
|
||||
title: language_str("saveFile"),
|
||||
filters: [{ name: 'Soon File Type', extensions: ['soon'] }],
|
||||
defaultPath: openAs.name || undefined
|
||||
}).then(result => {
|
||||
if (result.filePath == "") { return; }
|
||||
if (result.filePath == null || result.filePath == undefined) { return; }
|
||||
// 检查文件扩展名,确保以.soon结尾
|
||||
const path = require('path');
|
||||
let filePath = result.filePath;
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
if (ext !== '.soon') {
|
||||
filePath = filePath + '.soon';
|
||||
}).then(async function(result) {
|
||||
var fp = result.filePath || (result.fileHandle && result.fileHandle.name);
|
||||
if (!fp && !result.fileHandle) return;
|
||||
var pathExt = (typeof window !== 'undefined' && window.path && window.path.extname) ? window.path.extname(fp) : (fp.indexOf('.') >= 0 ? fp.slice(fp.lastIndexOf('.')) : '');
|
||||
if (pathExt !== '.soon') fp = (fp || 'design').replace(/\.soon$/i, '') + '.soon';
|
||||
var content = JSON.stringify(con_o);
|
||||
con_o.soonType = 1;
|
||||
if (window.platformBridge && window.platformBridge.writeFile) {
|
||||
await window.platformBridge.writeFile(result.fileHandle || fp, content);
|
||||
openAs.name = 'soondesign_session:' + fp;
|
||||
webSessionStore(content, fp);
|
||||
layer.msg(language_str("saveSucc") + fp);
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') callback();
|
||||
return;
|
||||
}
|
||||
result.filePath = filePath;
|
||||
let fs = require('fs')
|
||||
con_o.soonType = 1
|
||||
fs.writeFileSync(result.filePath, JSON.stringify(con_o), 'utf8')
|
||||
openAs.name = result.filePath;
|
||||
layer.msg(language_str("saveSucc") + openAs.name);//'保存成功至'
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback();
|
||||
var fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (fs) {
|
||||
fs.writeFileSync(result.filePath || fp, content, 'utf8');
|
||||
openAs.name = result.filePath || fp;
|
||||
layer.msg(language_str("saveSucc") + openAs.name);
|
||||
saveHistory();
|
||||
if (callback && typeof callback === 'function') callback();
|
||||
}
|
||||
}).catch(err => {
|
||||
})
|
||||
}).catch(function(err) {});
|
||||
}
|
||||
|
||||
// 网页端:保存前把当前内容写入 sessionStorage 与 localStorage,供首页历史读取(localStorage 跨标签/重开可用)
|
||||
function webSessionStore(content, fileName) {
|
||||
if (!window.platformBridge || typeof sessionStorage === 'undefined') return;
|
||||
var name = fileName || openAs.name || 'design.soon';
|
||||
var key = (name && name.indexOf('soondesign_session:') === 0) ? name : ('soondesign_session:' + name);
|
||||
try {
|
||||
sessionStorage.setItem(key, content);
|
||||
if (typeof localStorage !== 'undefined') localStorage.setItem(key, content);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 将 saveHistory 附加到 window 对象,确保在 ui.js 中也能访问
|
||||
window.saveHistory = function saveHistory() {
|
||||
let fs = require('fs');
|
||||
let j = { history: [] }; // 默认结构必须是数组
|
||||
|
||||
try {
|
||||
// 1. 读取并解析现有文件
|
||||
if (fs.existsSync(fullPath)) {
|
||||
let content = fs.readFileSync(fullPath).toString();
|
||||
// 防止空文件报错
|
||||
if (content.trim()) {
|
||||
j = JSON.parse(content);
|
||||
}
|
||||
function doWrite(j) {
|
||||
var currentPath = openAs.name;
|
||||
var pathForHistory = currentPath;
|
||||
if (window.platformBridge && (currentPath.indexOf('soondesign_session:') !== 0)) {
|
||||
pathForHistory = 'soondesign_session:' + (currentPath || 'design.soon');
|
||||
}
|
||||
var newList = (j.history || []).filter(function(item) { return item.path !== pathForHistory && item.path !== currentPath; });
|
||||
newList.unshift({ time: getDate(), path: pathForHistory, type: 1 });
|
||||
if (newList.length > 20) newList = newList.slice(0, 20);
|
||||
j.history = newList;
|
||||
if (window.platformBridge && window.platformBridge.writeHistory) {
|
||||
window.platformBridge.writeHistory(j);
|
||||
return;
|
||||
}
|
||||
var fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (fs && fullPath) {
|
||||
try { fs.writeFileSync(fullPath, JSON.stringify(j), 'utf8'); } catch (e) {}
|
||||
}
|
||||
} catch (e) {
|
||||
// 出错时使用默认空数组,不中断流程
|
||||
j = { history: [] };
|
||||
}
|
||||
|
||||
// 确保 j.history 是数组 (防御性编程)
|
||||
if (!Array.isArray(j.history)) {
|
||||
j.history = [];
|
||||
if (window.platformBridge && window.platformBridge.readHistory) {
|
||||
window.platformBridge.readHistory().then(function(j) {
|
||||
if (!j || !Array.isArray(j.history)) j = { history: [] };
|
||||
doWrite(j);
|
||||
}).catch(function() { doWrite({ history: [] }); });
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 【核心优化】先过滤掉当前文件(如果已存在),然后加到最前面
|
||||
// 这样可以实现“最近使用的文件排在第一位”的效果
|
||||
let currentPath = openAs.name;
|
||||
let newList = j.history.filter(item => item.path !== currentPath);
|
||||
|
||||
// 3. 插入到头部 (Unshift)
|
||||
newList.unshift({
|
||||
time: getDate(),
|
||||
path: currentPath,
|
||||
// type: 1 // 如果需要记录文件类型也可以加在这里
|
||||
});
|
||||
|
||||
// 4. (可选) 限制历史记录数量,比如只保留最近20条,防止文件无限膨胀
|
||||
if (newList.length > 20) {
|
||||
newList = newList.slice(0, 20);
|
||||
}
|
||||
|
||||
j.history = newList;
|
||||
|
||||
// 5. 统一写入
|
||||
try {
|
||||
fs.writeFileSync(fullPath, JSON.stringify(j), 'utf8');
|
||||
} catch (e) {
|
||||
var fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
var j = { history: [] };
|
||||
if (fs && fullPath) {
|
||||
try {
|
||||
if (fs.existsSync(fullPath)) {
|
||||
var content = fs.readFileSync(fullPath).toString();
|
||||
if (content.trim()) j = JSON.parse(content);
|
||||
}
|
||||
} catch (e) { j = { history: [] }; }
|
||||
}
|
||||
if (!Array.isArray(j.history)) j.history = [];
|
||||
doWrite(j);
|
||||
};
|
||||
// 向后兼容
|
||||
function saveHistory() {
|
||||
|
||||
+72
-54
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user