更新优化

This commit is contained in:
24kycj
2025-12-12 00:10:13 +08:00
parent 026d564c92
commit 50ff0d347a
34 changed files with 8669 additions and 7884 deletions
BIN
View File
Binary file not shown.
+434 -198
View File
@@ -5,7 +5,7 @@ require('./common/fabric-ext.js');
// 过滤 Canvas2D willReadFrequently 警告(不影响功能,只是性能提示)
if (typeof console !== 'undefined' && console.warn) {
const originalWarn = console.warn;
console.warn = function(...args) {
console.warn = function (...args) {
const message = args.join(' ');
// 过滤掉 willReadFrequently 相关的警告
if (message.includes('willReadFrequently') || message.includes('getImageData')) {
@@ -17,117 +17,219 @@ if (typeof console !== 'undefined' && console.warn) {
// Electron相关导入
const remote = require('@electron/remote');
var path = require('path');
var path = require('path');
const exePath = remote.app.getPath('userData');
const { ipcRenderer } = require('electron');
const { dialog } = require('@electron/remote');
var jrQrcode = require('jr-qrcode');
var JsBarcode = require('jsbarcode');
var jrQrcode = require('jr-qrcode');
var JsBarcode = require('jsbarcode');
const { clipboard } = require('electron');
const dpi = 600;
// 发送IPC消息
ipcRenderer.send('get-sys-fonts');
ipcRenderer.send('get-scale-rate');
ipcRenderer.send('get-sys-fonts');
ipcRenderer.send('get-scale-rate');
// 使用layui
layui.use(['layer', 'slider', 'form', 'colorpicker'], function () {
let myDate = new Date();
let s_lan = "";
ipcRenderer.send('get-sys-language');
layui.use(['layer', 'slider', 'form', 'colorpicker'], function () {
let myDate = new Date();
let s_lan = "";
// 确保 s_lan 在全局作用域中可用(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
ipcRenderer.send('get-sys-language');
var $ = layui.$;
var layer = layui.layer;
var slider = layui.slider;
var form = layui.form;
var colorpicker = layui.colorpicker;
// 确保所有必要的变量在全局作用域中可用(用于 .jsc 文件加载)
// 在 Electron 的渲染进程中,需要同时设置 window 和 global
if (typeof window !== 'undefined') {
window.$ = $;
window.jQuery = $;
window.ipcRenderer = ipcRenderer;
window.layer = layer;
window.slider = slider;
window.form = form;
window.colorpicker = colorpicker;
window.dialog = dialog;
window.remote = remote;
window.path = path;
window.jrQrcode = jrQrcode;
window.JsBarcode = JsBarcode;
window.clipboard = clipboard;
window.dpi = dpi;
// language_str 会在后面定义,但先确保引用正确
}
// 在 Node.js 上下文中也设置(require 加载 .jsc 文件时使用)
if (typeof global !== 'undefined') {
global.$ = $;
global.jQuery = $;
global.ipcRenderer = ipcRenderer;
global.layer = layer;
global.slider = slider;
global.form = form;
global.colorpicker = colorpicker;
global.dialog = dialog;
global.remote = remote;
global.path = path;
global.jrQrcode = jrQrcode;
global.JsBarcode = JsBarcode;
global.clipboard = clipboard;
global.dpi = dpi;
}
var layer = layui.layer;
var slider = layui.slider;
var colorpicker = layui.colorpicker;
// 历史记录文件路径(供 output.js 使用)
var fullPath = path.join(exePath, 'data.json');
// 确保 fullPath 在全局作用域中可用(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.fullPath = fullPath;
window.exePath = exePath;
}
if (typeof global !== 'undefined') {
global.fullPath = fullPath;
global.exePath = exePath;
}
// ==========================================
// 公共函数定义(需要在layui.use回调内部,因为依赖jQuery
// 注意:所有函数都附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
// ==========================================
// DES加密函数
window.desEncrypt = function desEncrypt(str, key = "df6a551ca43181fc485f3043bcdd2fbc") {
var APIFMS;
try {
// 确保输入字符串是 UTF-8 编码
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.DES.encrypt(str, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
// 使用 Base64 编码确保中文字符正确输出
APIFMS = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
} catch (err) {
console.log('des 加密错误:', err);
APIFMS = '';
}
return APIFMS;
};
// 向后兼容
function desEncrypt(str, key = "df6a551ca43181fc485f3043bcdd2fbc") {
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.DES.encrypt(str, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
return window.desEncrypt(str, key);
}
// 多语言切换
function langua_ge(lan = 'zh') {
$("[language='m']").each(function (i) {
$(this).html($(this).attr(lan));
window.langua_ge = function langua_ge(lan = 'zh') {
$("[language='m']").each(function (i) {
$(this).html($(this).attr(lan));
});
$("[language='t']").each(function (i) {
$(this).attr("title", $(this).attr(lan));
$("[language='t']").each(function (i) {
$(this).attr("title", $(this).attr(lan));
});
}
// 多语言字符串获取
function language_str(str) {
let t = {
"whetherSave": { zh: "是否保存当前文件?", ozh: "是否保存當前文件?", en: "Do you want to save the current file?" },
"save": { zh: "保存", ozh: "保存", en: "Save" },
"noSave": { zh: "不保存", ozh: "不保存", en: "No saving" },
"cancel": { zh: "取消", ozh: "取消", en: "Cancel" },
"saveSucc": { zh: "保存成功至", ozh: "保存成功至", en: "Save successfully to" },
"saveFile": { zh: "保存文件", ozh: "保存文件", en: "Save file" },
"display": { zh: "预览", ozh: "預覽", en: "Display" },
"output": { zh: "导出", ozh: "導出", en: "Export" },
"bg": { zh: "背景", ozh: "背景", en: "Background" },
"selectPic": { zh: "请选择图片", ozh: "請選擇圖片", en: "Please select a picture" },
"img": { zh: "圖片", ozh: "圖片", en: "Image" },
"simg": { zh: "合成圖片", ozh: "合成圖片", en: "Synthesized Image" },
"text": { zh: "文本", ozh: "文本", en: "Text" },
"ctext": { zh: "圆形文本", ozh: "圆形文本", en: "Circle Text" },
"stext": { zh: "合成文本", ozh: "合成文本", en: "Synthesized Text" },
"rect": { zh: "矩形", ozh: "矩形", en: "Rectangle" },
"circ": { zh: "圓形", ozh: "圓形", en: "Circle" },
"line": { zh: "直線", ozh: "直線", en: "Line" },
"qrc": { zh: "二維碼", ozh: "二維碼", en: "QR code" },
"barc": { zh: "條形碼", ozh: "條形碼", en: "Barcode" },
"counter": { zh: "計數器", ozh: "计数器", en: "Counter" },
"about": { zh: "关于Soon Design", ozh: "關於Soon Design", en: "About Soon Design" },
"vers": { zh: "版本", ozh: "版本", en: "Version" },
"comf": { zh: "确认", ozh: "確認", en: "Select" },
"copyright": { zh: "© 2022 cardsoon Co., Ltd. All rights reserved.", ozh: "© 2022 cardsoon Co., Ltd. All rights reserved.", en: "© 2022 cardsoon Co., Ltd. All rights reserved." }
};
return t[str] ? t[str][s_lan] : str;
};
// 向后兼容
function langua_ge(lan = 'zh') {
return window.langua_ge(lan);
}
// 多语言字符串获取
window.language_str = function language_str(str) {
let t = {
"whetherSave": { zh: "是否保存当前文件?", ozh: "是否保存當前文件?", en: "Do you want to save the current file?" },
"save": { zh: "保存", ozh: "保存", en: "Save" },
"noSave": { zh: "不保存", ozh: "不保存", en: "No saving" },
"cancel": { zh: "取消", ozh: "取消", en: "Cancel" },
"saveSucc": { zh: "保存成功至", ozh: "保存成功至", en: "Save successfully to" },
"saveFile": { zh: "保存文件", ozh: "保存文件", en: "Save file" },
"display": { zh: "预览", ozh: "預覽", en: "Display" },
"output": { zh: "导出", ozh: "導出", en: "Export" },
"bg": { zh: "背景", ozh: "背景", en: "Background" },
"selectPic": { zh: "请选择图片", ozh: "請選擇圖片", en: "Please select a picture" },
"img": { zh: "圖片", ozh: "圖片", en: "Image" },
"simg": { zh: "合成圖片", ozh: "合成圖片", en: "Synthesized Image" },
"text": { zh: "文本", ozh: "文本", en: "Text" },
"ctext": { zh: "圆形文本", ozh: "圆形文本", en: "Circle Text" },
"stext": { zh: "合成文本", ozh: "合成文本", en: "Synthesized Text" },
"rect": { zh: "矩形", ozh: "矩形", en: "Rectangle" },
"circ": { zh: "圓形", ozh: "圓形", en: "Circle" },
"line": { zh: "直線", ozh: "直線", en: "Line" },
"qrc": { zh: "二維碼", ozh: "二維碼", en: "QR code" },
"barc": { zh: "條形碼", ozh: "條形碼", en: "Barcode" },
"counter": { zh: "計數器", ozh: "计数器", en: "Counter" },
"about": { zh: "关于Soon Design", ozh: "關於Soon Design", en: "About Soon Design" },
"vers": { zh: "版本", ozh: "版本", en: "Version" },
"comf": { zh: "确认", ozh: "確認", en: "Select" },
"copyright": { zh: "© 2022 cardsoon Co., Ltd. All rights reserved.", ozh: "© 2022 cardsoon Co., Ltd. All rights reserved.", en: "© 2022 cardsoon Co., Ltd. All rights reserved." }
};
// 从全局作用域获取 s_lan(支持 .jsc 文件加载)
const currentLang = (typeof global !== 'undefined' && global.s_lan) ? global.s_lan :
(typeof window !== 'undefined' && window.s_lan) ? window.s_lan : s_lan;
return t[str] ? (t[str][currentLang] || t[str]['zh'] || str) : str;
};
// 确保 language_str 在 global 作用域中也可用(用于 .jsc 文件加载)
if (typeof global !== 'undefined') {
global.language_str = window.language_str;
}
// 向后兼容
function language_str(str) {
return window.language_str(str);
}
// 获取URL参数
function GetFile() {
window.GetFile = function GetFile() {
const params = new URLSearchParams(window.location.search);
return params;
};
// 向后兼容
function GetFile() {
return window.GetFile();
}
// 日期格式化
function getDate() {
let date = new Date();
return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
}
// 获取对象的绝对坐标
function getAbsoluteXY(_obj) {
let coord = _obj.get("lineCoords");
return [_obj.get("left"), _obj.get("top")];
window.getDate = function getDate() {
let date = new Date();
return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
};
// 向后兼容
function getDate() {
return window.getDate();
}
// 获取对象的绝对坐标
window.getAbsoluteXY = function getAbsoluteXY(_obj) {
let coord = _obj.get("lineCoords");
return [_obj.get("left"), _obj.get("top")];
};
// 向后兼容
function getAbsoluteXY(_obj) {
return window.getAbsoluteXY(_obj);
}
// 计算两点之间的距离
function getDisdance(x1, y1, x2, y2) {
window.getDisdance = function getDisdance(x1, y1, x2, y2) {
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var distance = Math.sqrt(dx * dx + dy * dy);
return distance;
};
// 向后兼容
function getDisdance(x1, y1, x2, y2) {
return window.getDisdance(x1, y1, x2, y2);
}
// 计算角度(相对于画布中心)
function getDeg(pointer, canvas) {
window.getDeg = function getDeg(pointer, canvas) {
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var mouseX = pointer.x;
@@ -141,130 +243,169 @@ const dpi = 600;
}
angleDeg += 90;
return angleDeg;
};
// 向后兼容
function getDeg(pointer, canvas) {
return window.getDeg(pointer, canvas);
}
// 检查字段名是否重复
window.checkName = function checkName(name, objs1, objs2) {
for (let item of objs1) {
if (item.name == name) {
return false;
}
}
for (let item of objs2) {
if (item.name == name) {
return false;
}
}
return true;
};
// 向后兼容
function checkName(name, objs1, objs2) {
for (let item of objs1) {
if (item.name == name) {
return false;
}
}
for (let item of objs2) {
if (item.name == name) {
return false;
}
}
return true;
}
return window.checkName(name, objs1, objs2);
}
// 返回不重复的字段名
window.resName = function resName(pre_name, objs1, objs2) {
let num = (objs1.length + objs2.length) - 1;
do {
num++;
}
while (!window.checkName(pre_name + num, objs1, objs2));
return pre_name + num;
};
// 向后兼容
function resName(pre_name, objs1, objs2) {
let num = (objs1.length + objs2.length) - 1;
do {
num++;
}
while (!checkName(pre_name + num, objs1, objs2));
return pre_name + num;
}
return window.resName(pre_name, objs1, objs2);
}
// 获取对象在画布中的索引
window.getIndex = function getIndex(target, canvas, _canvas = null) {
let temp_objs;
let useCanvas = (_canvas == null) ? canvas : _canvas;
if (_canvas == null) {
temp_objs = canvas.getObjects();
} else {
temp_objs = _canvas.getObjects();
}
let i = 0;
for (let res of temp_objs) {
if (target == res) {
return i;
}
i++;
}
return 0;
};
// 向后兼容
function getIndex(target, canvas, _canvas = null) {
let temp_objs;
let useCanvas = (_canvas == null) ? canvas : _canvas;
if (_canvas == null) {
temp_objs = canvas.getObjects();
} else {
temp_objs = _canvas.getObjects();
}
let i = 0;
for (let res of temp_objs) {
if (target == res) {
return i;
}
i++;
}
return 0;
}
return window.getIndex(target, canvas, _canvas);
}
// 获取对象类型
window.getType = function getType(target, canvas, objs) {
let temp_objs = canvas.getObjects();
let i = 0;
for (let res of temp_objs) {
if (target == res) {
return objs[i].type;
}
i++;
}
};
// 向后兼容
function getType(target, canvas, objs) {
let temp_objs = canvas.getObjects();
let i = 0;
for (let res of temp_objs) {
if (target == res) {
return objs[i].type;
}
i++;
}
}
return window.getType(target, canvas, objs);
}
// 获取坐标的最小X值
function getCoordsMinX(acoords) {
window.getCoordsMinX = function getCoordsMinX(acoords) {
let x = acoords[0].x;
for (let item of acoords) {
if (item.x < x) {
for (let item of acoords) {
if (item.x < x) {
x = item.x;
}
}
return x;
}
}
}
return x;
};
// 向后兼容
function getCoordsMinX(acoords) {
return window.getCoordsMinX(acoords);
}
// 获取坐标的最大X值
function getCoordsMaxX(acoords) {
window.getCoordsMaxX = function getCoordsMaxX(acoords) {
let x = acoords[0].x;
for (let item of acoords) {
if (item.x > x) {
for (let item of acoords) {
if (item.x > x) {
x = item.x;
}
}
return x;
}
}
}
return x;
};
// 向后兼容
function getCoordsMaxX(acoords) {
return window.getCoordsMaxX(acoords);
}
// 获取坐标的最小Y值
function getCoordsMinY(acoords) {
window.getCoordsMinY = function getCoordsMinY(acoords) {
let y = acoords[0].y;
for (let item of acoords) {
if (item.y < y) {
for (let item of acoords) {
if (item.y < y) {
y = item.y;
}
}
return y;
}
}
}
return y;
};
// 向后兼容
function getCoordsMinY(acoords) {
return window.getCoordsMinY(acoords);
}
// 获取坐标的最大Y值
function getCoordsMaxY(acoords) {
window.getCoordsMaxY = function getCoordsMaxY(acoords) {
let y = acoords[0].y;
for (let item of acoords) {
if (item.y > y) {
for (let item of acoords) {
if (item.y > y) {
y = item.y;
}
}
return y;
}
}
}
return y;
};
// 向后兼容
function getCoordsMaxY(acoords) {
return window.getCoordsMaxY(acoords);
}
// ==========================================
// 全局变量定义(所有模块共享)
// 注意:所有变量都附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
// ==========================================
let addState = 0; // 0是不添加
let background_image, background_image1, background_image2;
let bg_version = 1; // front_bg1.png front_bg2.png
var zoom = 1;
let pre_add_image; // 预添加的图片对象(用于addPic)
window.addState = 0; // 0是不添加
window.background_image = undefined;
window.background_image1 = undefined;
window.background_image2 = undefined;
window.bg_version = 1; // front_bg1.png front_bg2.png
window.zoom = 1;
window.pre_add_image = undefined; // 预添加的图片对象(用于addPic)
// 内部剪贴板
let clipboardData = {
window.clipboardData = {
data: null,
offset: 10 // 粘贴位置偏移量
};
// 文件管理
var openAs = {
window.openAs = {
_name: "",
set name(val) {
if (val == "") {
$("title").html('Soon Design');
} else {
} else {
$("title").html('Soon Design - ' + val);
}
this._name = val;
@@ -273,48 +414,143 @@ const dpi = 600;
return this._name
},
};
// 对象数组和历史记录
let objs1 = [];
let objs2 = [];
let step1 = { val: 0 }, step2 = { val: 0 };
let step = step1;
let objs = objs1;
let recordJson1 = [], recordJson2 = [], recordJson = recordJson1, recordObjs1 = [], recordObjs2 = [], recordObjs = recordObjs1;
let pre_objs1 = [], pre_objs2 = [], next_objs1 = [], next_objs2 = [], pre_objs = pre_objs1, next_objs = next_objs1;
let pre_json1 = [], pre_json2 = [], next_json1 = [], next_json2 = [], pre_json = pre_json1, next_json = next_json1;
window.objs1 = [];
window.objs2 = [];
window.step1 = { val: 0 };
window.step2 = { val: 0 };
window.step = window.step1;
window.objs = window.objs1;
window.recordJson1 = [];
window.recordJson2 = [];
window.recordJson = window.recordJson1;
window.recordObjs1 = [];
window.recordObjs2 = [];
window.recordObjs = window.recordObjs1;
window.pre_objs1 = [];
window.pre_objs2 = [];
window.next_objs1 = [];
window.next_objs2 = [];
window.pre_objs = window.pre_objs1;
window.next_objs = window.next_objs1;
window.pre_json1 = [];
window.pre_json2 = [];
window.next_json1 = [];
window.next_json2 = [];
window.pre_json = window.pre_json1;
window.next_json = window.next_json1;
// Canvas对象(将在core.js中初始化)
var canvas1, canvas2;
var canvas; // 当前活动的画布(canvas1 或 canvas2
var ctx1, ctx2;
let is_bgi_add = false;
window.canvas1 = undefined;
window.canvas2 = undefined;
window.canvas = undefined; // 当前活动的画布(canvas1 或 canvas2
window.ctx1 = undefined;
window.ctx2 = undefined;
window.is_bgi_add = false;
// 为了兼容性,同时创建局部变量引用(向后兼容)
let addState = window.addState;
let background_image = window.background_image;
let background_image1 = window.background_image1;
let background_image2 = window.background_image2;
let bg_version = window.bg_version;
var zoom = window.zoom;
let pre_add_image = window.pre_add_image;
let clipboardData = window.clipboardData;
var openAs = window.openAs;
let objs1 = window.objs1;
let objs2 = window.objs2;
let step1 = window.step1;
let step2 = window.step2;
let step = window.step;
let objs = window.objs;
let recordJson1 = window.recordJson1;
let recordJson2 = window.recordJson2;
let recordJson = window.recordJson;
let recordObjs1 = window.recordObjs1;
let recordObjs2 = window.recordObjs2;
let recordObjs = window.recordObjs;
let pre_objs1 = window.pre_objs1;
let pre_objs2 = window.pre_objs2;
let next_objs1 = window.next_objs1;
let next_objs2 = window.next_objs2;
let pre_objs = window.pre_objs;
let next_objs = window.next_objs;
let pre_json1 = window.pre_json1;
let pre_json2 = window.pre_json2;
let next_json1 = window.next_json1;
let next_json2 = window.next_json2;
let pre_json = window.pre_json;
let next_json = window.next_json;
var canvas1 = window.canvas1;
var canvas2 = window.canvas2;
var canvas = window.canvas;
var ctx1 = window.ctx1;
var ctx2 = window.ctx2;
let is_bgi_add = window.is_bgi_add;
// 加载design1模块
// 由于模块代码需要在layui.use内部执行,我们通过动态加载的方式
const fs = require('fs');
// 加载core.js(核心功能)
let bytenode;
try {
bytenode = require('bytenode');
require.extensions['.dl'] = require.extensions['.jsc'];
} catch (e) {
console.warn('[加载模块] bytenode 未安装,无法加载 .jsc 文件');
}
const appPath = (() => { try { return remote.app.getAppPath(); } catch (e) { return __dirname || process.cwd(); } })();
// 读取模块映射配置(从 lib 目录读取,跨平台兼容)
let moduleMap = {};
try {
const coreCode = fs.readFileSync(__dirname + '/design1/core.js', 'utf8');
eval(coreCode);
const moduleMapPath = path.join(appPath, 'lib', 'module-map.json');
if (fs.existsSync(moduleMapPath)) {
moduleMap = JSON.parse(fs.readFileSync(moduleMapPath, 'utf8'));
}
} catch (e) {
console.error('加载core.js失败:', e);
console.warn('[加载模块] 无法读取模块映射配置,使用默认文件名');
}
// 加载output.js(输出功能,需要在ui.js之前加载,因为ui.js中的saveAs会调用output.js中的函数
try {
const outputCode = fs.readFileSync(__dirname + '/design1/output.js', 'utf8');
eval(outputCode);
} catch (e) {
console.error('加载output.js失败:', e);
}
// 加载ui.jsUI控制)
try {
const uiCode = fs.readFileSync(__dirname + '/design1/ui.js', 'utf8');
eval(uiCode);
} catch (e) {
console.error('加载ui.js失败:', e);
// 获取映射后的文件名(跨平台兼容
function getMappedFileName(moduleName) {
if (moduleMap.mappings && moduleMap.mappings.design1 && moduleMap.mappings.design1[moduleName]) {
return moduleMap.mappings.design1[moduleName];
}
return moduleName; // 默认使用原文件名
}
const loadModule = (moduleName) => {
const mappedName = getMappedFileName(moduleName);
const jscPath = path.join(appPath, 'lib', 'design1', `${mappedName}.jsc`);
const jsPath = path.join(appPath, 'lib', 'design1', `${moduleName}.js`);
// 优先加载映射的 .jsc 文件
if (fs.existsSync(jscPath) && bytenode) {
try {
require(jscPath);
console.log(`[加载模块] ✅ ${moduleName}${mappedName}.jsc`);
return;
} catch (e) {
console.error(`[加载模块] ❌ ${moduleName}.jsc 加载失败:`, e.message);
}
}
// 回退到 .js 源文件
if (fs.existsSync(jsPath)) {
try {
eval(fs.readFileSync(jsPath, 'utf8'));
console.log(`[加载模块] ✅ ${moduleName}${moduleName}.js`);
} catch (e) {
console.error(`[加载模块] ❌ ${moduleName}.js 加载失败:`, e.message);
alert(`加载 ${moduleName} 失败!\n\n错误: ${e.message}`);
}
} else {
alert(`文件不存在!\n\n请检查:\n1. ${jscPath}\n2. ${jsPath}`);
}
};
loadModule('output'); // 先加载 output,因为 core 中的 addBackground() 需要调用 output 中的 open()
loadModule('core');
loadModule('ui');
});
+236 -951
View File
File diff suppressed because it is too large Load Diff
+318 -199
View File
File diff suppressed because one or more lines are too long
+2338 -2092
View File
File diff suppressed because one or more lines are too long
+279 -55
View File
@@ -38,17 +38,67 @@ ipcRenderer.send('get-scale-rate');
var $ = layui.$;
var layer = layui.layer;
var slider = layui.slider;
var form = layui.form;
var colorpicker = layui.colorpicker;
// 确保所有必要的变量在全局作用域中可用(用于 .jsc 文件加载)
// 在 Electron 的渲染进程中,需要同时设置 window 和 global
if (typeof window !== 'undefined') {
window.$ = $;
window.jQuery = $;
window.ipcRenderer = ipcRenderer;
window.layer = layer;
window.slider = slider;
window.form = form;
window.colorpicker = colorpicker;
window.dialog = dialog;
window.remote = remote;
window.path = path;
window.jrQrcode = jrQrcode;
window.JsBarcode = JsBarcode;
window.clipboard = clipboard;
// design2 中没有定义 dpi,从 window.dpi 读取(在 design2.js 后面会设置)
}
// 在 Node.js 上下文中也设置(require 加载 .jsc 文件时使用)
if (typeof global !== 'undefined') {
global.$ = $;
global.jQuery = $;
global.ipcRenderer = ipcRenderer;
global.layer = layer;
global.slider = slider;
global.form = form;
global.colorpicker = colorpicker;
global.dialog = dialog;
global.remote = remote;
global.path = path;
global.jrQrcode = jrQrcode;
global.JsBarcode = JsBarcode;
global.clipboard = clipboard;
// design2 中没有定义 dpi,从 global.dpi 读取(在 design2.js 后面会设置)
}
var layer = layui.layer;
var slider = layui.slider;
var colorpicker = layui.colorpicker;
// 历史记录文件路径(供 output.js 使用)
var fullPath = path.join(exePath, 'data.json');
// 确保 fullPath 在全局作用域中可用(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.fullPath = fullPath;
window.exePath = exePath;
}
if (typeof global !== 'undefined') {
global.fullPath = fullPath;
global.exePath = exePath;
}
// ==========================================
// 公共函数定义(需要在layui.use回调内部,因为依赖jQuery
// 注意:所有函数都附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
// ==========================================
// DES加密函数
function desEncrypt(str, key = "df6a551ca43181fc485f3043bcdd2fbc") {
window.desEncrypt = function desEncrypt(str, key = "df6a551ca43181fc485f3043bcdd2fbc") {
var APIFMS;
try {
var keyHex_encrypt = CryptoJS.enc.Utf8.parse(key);
@@ -62,20 +112,28 @@ ipcRenderer.send('get-scale-rate');
console.log(err);
}
return APIFMS;
};
// 向后兼容
function desEncrypt(str, key = "df6a551ca43181fc485f3043bcdd2fbc") {
return window.desEncrypt(str, key);
}
// 多语言切换
function langua_ge(lan = 'zh') {
window.langua_ge = function langua_ge(lan = 'zh') {
$("[language='m']").each(function (i) {
$(this).html($(this).attr(lan));
});
$("[language='t']").each(function (i) {
$(this).attr("title", $(this).attr(lan));
});
};
// 向后兼容
function langua_ge(lan = 'zh') {
return window.langua_ge(lan);
}
// 多语言字符串获取
function language_str(str) {
window.language_str = function language_str(str) {
let t = {
"whetherSave": { zh: "是否保存当前文件?", ozh: "是否保存當前文件?", en: "Do you want to save the current file?" },
"save": { zh: "保存", ozh: "保存", en: "Save" },
@@ -103,37 +161,64 @@ ipcRenderer.send('get-scale-rate');
"comf": { zh: "确认", ozh: "確認", en: "Select" },
"copyright": { zh: "© 2022 cardsoon Co., Ltd. All rights reserved.", ozh: "© 2022 cardsoon Co., Ltd. All rights reserved.", en: "© 2022 cardsoon Co., Ltd. All rights reserved." }
};
return t[str] ? t[str][s_lan] : str;
// 从全局作用域获取 s_lan(支持 .jsc 文件加载)
const currentLang = (typeof global !== 'undefined' && global.s_lan) ? global.s_lan :
(typeof window !== 'undefined' && window.s_lan) ? window.s_lan : s_lan;
return t[str] ? (t[str][currentLang] || t[str]['zh'] || str) : str;
};
// 确保 language_str 在 global 作用域中也可用(用于 .jsc 文件加载)
if (typeof global !== 'undefined') {
global.language_str = window.language_str;
}
// 向后兼容
function language_str(str) {
return window.language_str(str);
}
// 获取URL参数
function GetFile() {
window.GetFile = function GetFile() {
const params = new URLSearchParams(window.location.search);
return params;
};
// 向后兼容
function GetFile() {
return window.GetFile();
}
// 日期格式化
function getDate() {
window.getDate = function getDate() {
let date = new Date();
return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
};
// 向后兼容
function getDate() {
return window.getDate();
}
// 获取对象的绝对坐标
function getAbsoluteXY(_obj) {
window.getAbsoluteXY = function getAbsoluteXY(_obj) {
let coord = _obj.get("lineCoords");
return [_obj.get("left"), _obj.get("top")];
};
// 向后兼容
function getAbsoluteXY(_obj) {
return window.getAbsoluteXY(_obj);
}
// 计算两点之间的距离
function getDisdance(x1, y1, x2, y2) {
window.getDisdance = function getDisdance(x1, y1, x2, y2) {
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var distance = Math.sqrt(dx * dx + dy * dy);
return distance;
};
// 向后兼容
function getDisdance(x1, y1, x2, y2) {
return window.getDisdance(x1, y1, x2, y2);
}
// 计算角度(相对于画布中心)
function getDeg(pointer, canvas) {
window.getDeg = function getDeg(pointer, canvas) {
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var mouseX = pointer.x;
@@ -147,10 +232,14 @@ ipcRenderer.send('get-scale-rate');
}
angleDeg += 90;
return angleDeg;
};
// 向后兼容
function getDeg(pointer, canvas) {
return window.getDeg(pointer, canvas);
}
// 检查字段名是否重复
function checkName(name, objs1, objs2) {
window.checkName = function checkName(name, objs1, objs2) {
for (let item of objs1) {
if (item.name == name) {
return false;
@@ -162,20 +251,28 @@ ipcRenderer.send('get-scale-rate');
}
}
return true;
};
// 向后兼容
function checkName(name, objs1, objs2) {
return window.checkName(name, objs1, objs2);
}
// 返回不重复的字段名
function resName(pre_name, objs1, objs2) {
window.resName = function resName(pre_name, objs1, objs2) {
let num = (objs1.length + objs2.length) - 1;
do {
num++;
}
while (!checkName(pre_name + num, objs1, objs2));
while (!window.checkName(pre_name + num, objs1, objs2));
return pre_name + num;
};
// 向后兼容
function resName(pre_name, objs1, objs2) {
return window.resName(pre_name, objs1, objs2);
}
// 获取对象在画布中的索引
function getIndex(target, canvas, _canvas = null) {
window.getIndex = function getIndex(target, canvas, _canvas = null) {
let temp_objs;
if (_canvas == null) {
temp_objs = canvas.getObjects();
@@ -190,10 +287,14 @@ ipcRenderer.send('get-scale-rate');
i++;
}
return 0;
};
// 向后兼容
function getIndex(target, canvas, _canvas = null) {
return window.getIndex(target, canvas, _canvas);
}
// 获取对象类型
function getType(target, canvas, objs) {
window.getType = function getType(target, canvas, objs) {
let temp_objs = canvas.getObjects();
let i = 0;
for (let res of temp_objs) {
@@ -202,10 +303,14 @@ ipcRenderer.send('get-scale-rate');
}
i++;
}
};
// 向后兼容
function getType(target, canvas, objs) {
return window.getType(target, canvas, objs);
}
// 获取坐标的最小X值
function getCoordsMinX(acoords) {
window.getCoordsMinX = function getCoordsMinX(acoords) {
let x = acoords[0].x;
for (let item of acoords) {
if (item.x < x) {
@@ -213,10 +318,14 @@ ipcRenderer.send('get-scale-rate');
}
}
return x;
};
// 向后兼容
function getCoordsMinX(acoords) {
return window.getCoordsMinX(acoords);
}
// 获取坐标的最大X值
function getCoordsMaxX(acoords) {
window.getCoordsMaxX = function getCoordsMaxX(acoords) {
let x = acoords[0].x;
for (let item of acoords) {
if (item.x > x) {
@@ -224,10 +333,14 @@ ipcRenderer.send('get-scale-rate');
}
}
return x;
};
// 向后兼容
function getCoordsMaxX(acoords) {
return window.getCoordsMaxX(acoords);
}
// 获取坐标的最小Y值
function getCoordsMinY(acoords) {
window.getCoordsMinY = function getCoordsMinY(acoords) {
let y = acoords[0].y;
for (let item of acoords) {
if (item.y < y) {
@@ -235,10 +348,14 @@ ipcRenderer.send('get-scale-rate');
}
}
return y;
};
// 向后兼容
function getCoordsMinY(acoords) {
return window.getCoordsMinY(acoords);
}
// 获取坐标的最大Y值
function getCoordsMaxY(acoords) {
window.getCoordsMaxY = function getCoordsMaxY(acoords) {
let y = acoords[0].y;
for (let item of acoords) {
if (item.y > y) {
@@ -246,26 +363,37 @@ ipcRenderer.send('get-scale-rate');
}
}
return y;
};
// 向后兼容
function getCoordsMaxY(acoords) {
return window.getCoordsMaxY(acoords);
}
// ==========================================
// 全局变量定义(所有模块共享)
// 注意:所有变量都附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
// ==========================================
const dpi = 300; // design2使用300 DPI
let addState = 0; // 0是不添加
let background_image, background_image1, background_image2;
let bg_version = 1;
var zoom = 0;
let pre_add_image; // 预添加的图片对象(用于addPic)
window.dpi = 300; // design2使用300 DPI
// 确保 dpi 在 global 作用域中也可用(用于 .jsc 文件加载)
if (typeof global !== 'undefined') {
global.dpi = window.dpi;
}
window.addState = 0; // 0是不添加
window.background_image = undefined;
window.background_image1 = undefined;
window.background_image2 = undefined;
window.bg_version = 1;
window.zoom = 0;
window.pre_add_image = undefined; // 预添加的图片对象(用于addPic)
// 内部剪贴板
let clipboardData = {
window.clipboardData = {
data: null,
offset: 10 // 粘贴位置偏移量
};
// 文件管理
var openAs = {
window.openAs = {
_name: "",
set name(val) {
if (val == "") {
@@ -281,46 +409,142 @@ ipcRenderer.send('get-scale-rate');
};
// 对象数组和历史记录
let objs1 = [];
let objs2 = [];
let step1 = { val: 0 }, step2 = { val: 0 };
let step = step1;
let objs = objs1;
let recordJson1 = [], recordJson2 = [], recordJson = recordJson1, recordObjs1 = [], recordObjs2 = [], recordObjs = recordObjs1;
let pre_objs1 = [], pre_objs2 = [], next_objs1 = [], next_objs2 = [], pre_objs = pre_objs1, next_objs = next_objs1;
let pre_json1 = [], pre_json2 = [], next_json1 = [], next_json2 = [], pre_json = pre_json1, next_json = next_json1;
window.objs1 = [];
window.objs2 = [];
window.step1 = { val: 0 };
window.step2 = { val: 0 };
window.step = window.step1;
window.objs = window.objs1;
window.recordJson1 = [];
window.recordJson2 = [];
window.recordJson = window.recordJson1;
window.recordObjs1 = [];
window.recordObjs2 = [];
window.recordObjs = window.recordObjs1;
window.pre_objs1 = [];
window.pre_objs2 = [];
window.next_objs1 = [];
window.next_objs2 = [];
window.pre_objs = window.pre_objs1;
window.next_objs = window.next_objs1;
window.pre_json1 = [];
window.pre_json2 = [];
window.next_json1 = [];
window.next_json2 = [];
window.pre_json = window.pre_json1;
window.next_json = window.next_json1;
// Canvas对象(将在core.js中初始化)
var canvas1, canvas2;
var canvas; // 当前活动的画布(canvas1 或 canvas2
var ctx1, ctx2;
let is_bgi_add = false;
window.canvas1 = undefined;
window.canvas2 = undefined;
window.canvas = undefined; // 当前活动的画布(canvas1 或 canvas2
window.ctx1 = undefined;
window.ctx2 = undefined;
window.is_bgi_add = false;
// 为了兼容性,同时创建局部变量引用(向后兼容)
const dpi = window.dpi;
let addState = window.addState;
let background_image = window.background_image;
let background_image1 = window.background_image1;
let background_image2 = window.background_image2;
let bg_version = window.bg_version;
var zoom = window.zoom;
let pre_add_image = window.pre_add_image;
let clipboardData = window.clipboardData;
var openAs = window.openAs;
let objs1 = window.objs1;
let objs2 = window.objs2;
let step1 = window.step1;
let step2 = window.step2;
let step = window.step;
let objs = window.objs;
let recordJson1 = window.recordJson1;
let recordJson2 = window.recordJson2;
let recordJson = window.recordJson;
let recordObjs1 = window.recordObjs1;
let recordObjs2 = window.recordObjs2;
let recordObjs = window.recordObjs;
let pre_objs1 = window.pre_objs1;
let pre_objs2 = window.pre_objs2;
let next_objs1 = window.next_objs1;
let next_objs2 = window.next_objs2;
let pre_objs = window.pre_objs;
let next_objs = window.next_objs;
let pre_json1 = window.pre_json1;
let pre_json2 = window.pre_json2;
let next_json1 = window.next_json1;
let next_json2 = window.next_json2;
let pre_json = window.pre_json;
let next_json = window.next_json;
var canvas1 = window.canvas1;
var canvas2 = window.canvas2;
var canvas = window.canvas;
var ctx1 = window.ctx1;
var ctx2 = window.ctx2;
let is_bgi_add = window.is_bgi_add;
// 加载design2模块
// 由于模块代码需要在layui.use内部执行,我们通过动态加载的方式
const fs = require('fs');
// 加载core.js(核心功能)
try {
const coreCode = fs.readFileSync(__dirname + '/design2/core.js', 'utf8');
eval(coreCode);
} catch (e) {
console.error('加载core.js失败:', e);
let bytenode;
try {
bytenode = require('bytenode');
require.extensions['.dl'] = require.extensions['.jsc'];
} catch(e) {
console.warn('[加载模块] bytenode 未安装,无法加载 .jsc 文件');
}
// 加载ui.jsUI控制)
const appPath = (() => { try { return remote.app.getAppPath(); } catch(e) { return __dirname || process.cwd(); } })();
// 读取模块映射配置
let moduleMap = {};
try {
const uiCode = fs.readFileSync(__dirname + '/design2/ui.js', 'utf8');
eval(uiCode);
const moduleMapPath = path.join(appPath, 'lib', 'module-map.json');
if (fs.existsSync(moduleMapPath)) {
moduleMap = JSON.parse(fs.readFileSync(moduleMapPath, 'utf8'));
}
} catch (e) {
console.error('加载ui.js失败:', e);
console.warn('[加载模块] 无法读取模块映射配置,使用默认文件名');
}
// 加载output.js(输出功能
try {
const outputCode = fs.readFileSync(__dirname + '/design2/output.js', 'utf8');
eval(outputCode);
// 获取映射后的文件名(跨平台兼容
function getMappedFileName(moduleName) {
if (moduleMap.mappings && moduleMap.mappings.design2 && moduleMap.mappings.design2[moduleName]) {
return moduleMap.mappings.design2[moduleName];
}
return moduleName; // 默认使用原文件名
}
const loadModule = (moduleName) => {
const mappedName = getMappedFileName(moduleName);
const jscPath = path.join(appPath, 'lib', 'design2', `${mappedName}.jsc`);
const jsPath = path.join(appPath, 'lib', 'design2', `${moduleName}.js`);
// 优先加载映射的 .jsc 文件
if (fs.existsSync(jscPath) && bytenode) {
try {
require(jscPath);
console.log(`[加载模块] ✅ ${moduleName}${mappedName}.jsc`);
return;
} catch (e) {
console.error(`[加载模块] ❌ ${moduleName}.jsc 加载失败:`, e.message);
}
}
// 回退到 .js 源文件
if (fs.existsSync(jsPath)) {
try {
eval(fs.readFileSync(jsPath, 'utf8'));
console.log(`[加载模块] ✅ ${moduleName}${moduleName}.js`);
} catch (e) {
console.error('加载output.js失败:', e);
console.error(`[加载模块] ❌ ${moduleName}.js 加载失败:`, e.message);
alert(`加载 ${moduleName} 失败!\n\n错误: ${e.message}`);
}
} else {
alert(`文件不存在!\n\n请检查:\n1. ${jscPath}\n2. ${jsPath}`);
}
};
loadModule('output'); // 先加载 output,因为 core 中的 addBackground() 需要调用 output 中的 open()
loadModule('core');
loadModule('ui');
});
+256 -957
View File
File diff suppressed because it is too large Load Diff
+178 -69
View File
@@ -1,4 +1,5 @@
function display_func(img1, img2, img3) {
// 将 display_func 附加到 window 对象,确保全局可访问
window.display_func = function display_func(img1, img2, img3) {
$('#base_control').hide()
$('#line_control').hide()
$('#pic_control').hide()
@@ -15,6 +16,27 @@ function display_func(img1, img2, img3) {
$('#component_type').text(language_str('bg')) //"背景"
canvas1.discardActiveObject().renderAll()
canvas2.discardActiveObject().renderAll()
// 保存所有对象的 selectable 和 evented 状态,确保预览后能恢复
const objStates1 = [];
const objStates2 = [];
canvas1.getObjects().forEach((obj, index) => {
if (!obj.isGuideLine) {
objStates1[index] = {
selectable: obj.selectable,
evented: obj.evented
};
}
});
canvas2.getObjects().forEach((obj, index) => {
if (!obj.isGuideLine) {
objStates2[index] = {
selectable: obj.selectable,
evented: obj.evented
};
}
});
// 过滤掉辅助线
let _objs1 = canvas1.getObjects().filter(obj => !obj.isGuideLine)
let g1 = []
@@ -30,7 +52,7 @@ function display_func(img1, img2, img3) {
let list1 = _objs1.filter(obj => !obj.isGuideLine)
for (let item of list1) {
let idx = getIndex(item, canvas1)
// 安全检查:确保 objs1[idx - 1] 存在且有 type 属性
if (idx != 0 && (!objs1[idx - 1] || typeof objs1[idx - 1].type === 'undefined')) {
continue
@@ -114,10 +136,9 @@ function display_func(img1, img2, img3) {
})
// g3.push(img1)
// 预览图缩小尺寸以减小文件大小,使用 multiplier 来缩放整个 Group,保持所有内容完整
let url3 = new fabric.Group(g3).toDataURL({
format: 'png',
multiplier: 0.6, // 缩小到原来的 60%,保持宽高比和所有内容
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
@@ -142,7 +163,7 @@ function display_func(img1, img2, img3) {
let filteredObjs2 = _objs2.filter(obj => !obj.isGuideLine)
for (let item of filteredObjs2) {
let idx = getIndex(item, canvas2)
// 安全检查:确保 objs2[idx - 1] 存在且有 type 属性
if (idx != 0 && (!objs2[idx - 1] || typeof objs2[idx - 1].type === 'undefined')) {
continue
@@ -225,10 +246,9 @@ function display_func(img1, img2, img3) {
width: 1012
})
// g4.push(img2)
// 预览图缩小尺寸以减小文件大小,使用 multiplier 来缩放整个 Group,保持所有内容完整
let url4 = new fabric.Group(g4).toDataURL({
format: 'png',
multiplier: 0.6, // 缩小到原来的 60%,保持宽高比和所有内容
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
@@ -323,23 +343,53 @@ function display_func(img1, img2, img3) {
</div>`,
btn: btns, //'导出'
btn1: function (index, layero) {
savePdf(Buffer.from(pdfBuffer))
// 只处理导出(保存PDF
if (typeof window.savePdf === 'function') {
window.savePdf(Buffer.from(pdfBuffer));
} else {
console.error('savePdf 函数未定义!');
}
},
btn2: function () {
// 根据 btns[1] 的值决定打印哪一面
if (btns[1] === '打印正面') {
// 打印正面
printJS({ printable: printPath3, type: 'image', style: 'img { width: 100%; height: auto; }' })
} else {
} else if (btns[1] === '打印背面') {
// 打印背面(只有背面时)
printJS({ printable: printPath4, type: 'image', style: 'img { width: 100%; height: auto; }' })
}
},
btn3: function () {
//打印背面
// 打印背面(两面都有时,btn3 对应 btns[2] = '打印背面'
printJS({ printable: printPath4, type: 'image', style: 'img { width: 100%; height: auto; }' })
},
end: function() {
// 预览窗口关闭后,恢复所有对象的 selectable 和 evented 状态
canvas1.getObjects().forEach((obj, index) => {
if (!obj.isGuideLine && objStates1[index]) {
obj.set({
selectable: objStates1[index].selectable,
evented: objStates1[index].evented
});
}
});
canvas2.getObjects().forEach((obj, index) => {
if (!obj.isGuideLine && objStates2[index]) {
obj.set({
selectable: objStates2[index].selectable,
evented: objStates2[index].evented
});
}
});
canvas1.renderAll();
canvas2.renderAll();
}
})
}
function output(callback = null, _save = save) {
// 将 output 附加到 window 对象,确保全局可访问
window.output = function output(callback = null, _save = save) {
// 类型改变
fabric.Image.fromURL('./public/images/op_2.png', function (i1) {
i1.left = background_image.left
@@ -380,7 +430,7 @@ function output(callback = null, _save = save) {
// _objs1 已经在上面过滤过辅助线了,直接使用
for (let item of _objs1) {
let idx = getIndex(item, canvas1)
// 安全检查:确保 objs1[idx - 1] 存在且有 type 属性
if (idx != 0 && (!objs1[idx - 1] || typeof objs1[idx - 1].type === 'undefined')) {
continue
@@ -464,10 +514,9 @@ function output(callback = null, _save = save) {
left: left / zoom
})
g3.push(img1)
// 预览图缩小尺寸以减小文件大小,使用 multiplier 来缩放整个 Group,保持所有内容完整
let url3 = new fabric.Group(g3).toDataURL({
format: 'png',
multiplier: 0.6, // 缩小到原来的 60%,保持宽高比和所有内容
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
@@ -491,7 +540,7 @@ function output(callback = null, _save = save) {
// _objs2 已经在上面过滤过辅助线了,直接使用
for (let item of _objs2) {
let idx = getIndex(item, canvas2)
// 安全检查:确保 objs2[idx - 1] 存在且有 type 属性
if (idx != 0 && (!objs2[idx - 1] || typeof objs2[idx - 1].type === 'undefined')) {
continue
@@ -571,10 +620,9 @@ function output(callback = null, _save = save) {
width: 1012
})
g4.push(img2)
// 预览图缩小尺寸以减小文件大小,使用 multiplier 来缩放整个 Group,保持所有内容完整
let url4 = new fabric.Group(g4).toDataURL({
format: 'png',
multiplier: 0.6, // 缩小到原来的 60%,保持宽高比和所有内容
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
@@ -615,7 +663,7 @@ function output(callback = null, _save = save) {
// _objs1 已经在上面过滤过辅助线了,直接使用
for (let item of _objs1) {
let idx = getIndex(item, canvas1)
// 安全检查:确保 objs1[idx - 1] 存在且有 type 属性
if (idx != 0 && (!objs1[idx - 1] || typeof objs1[idx - 1].type === 'undefined')) {
continue
@@ -758,7 +806,7 @@ function output(callback = null, _save = save) {
// _objs2 已经在上面过滤过辅助线了,直接使用
for (let item of _objs2) {
let idx = getIndex(item, canvas2)
// 安全检查:确保 objs2[idx - 1] 存在且有 type 属性
if (idx != 0 && (!objs2[idx - 1] || typeof objs2[idx - 1].type === 'undefined')) {
continue
@@ -902,43 +950,44 @@ function output(callback = null, _save = save) {
}
// 重新生成二维码和条形码(加载文件后调用)
function regenerateQrCodesAndBarcodes(canvas, objsArray) {
// 将 regenerateQrCodesAndBarcodes 附加到 window 对象,确保全局可访问
window.regenerateQrCodesAndBarcodes = function regenerateQrCodesAndBarcodes(canvas, objsArray) {
if (!canvas || !objsArray || !Array.isArray(objsArray)) return
const objects = canvas.getObjects()
// 遍历对象(跳过背景图片,索引 0)
for (let i = 1; i < objects.length; i++) {
const obj = objects[i]
if (!obj || obj.type !== 'image') continue
const objIndex = i - 1
if (objIndex >= objsArray.length) continue
const objMeta = objsArray[objIndex]
if (!objMeta || (objMeta.type !== 8 && objMeta.type !== 9)) continue
// type == 8: 二维码 - 复用 ui.js 中的生成逻辑
if (objMeta.type === 8) {
const qr = jrQrcode.getQrBase64(objMeta.val || 'https://www.cardsoon.com', {
padding: 0,
foreground: objMeta.color || '#000000'
const qr = jrQrcode.getQrBase64(objMeta.val || 'https://www.cardsoon.com', {
padding: 0,
foreground: objMeta.color || '#000000'
})
obj.setSrc(qr, function(img) {
obj.setSrc(qr, function (img) {
canvas.renderAll()
})
}
// type == 9: 条形码 - 复用 ui.js 中的生成逻辑
else if (objMeta.type === 9) {
JsBarcode("#barcode", objMeta.val || '123456789', {
margin: 0,
lineColor: objMeta.color || '#000000',
fontSize: objMeta.fontSize || 18,
font: objMeta.font || 'Arial'
JsBarcode("#barcode", objMeta.val || '123456789', {
margin: 0,
lineColor: objMeta.color || '#000000',
fontSize: objMeta.fontSize || 18,
font: objMeta.font || 'Arial'
})
const barcode = document.getElementById('barcode')
const bar = barcode.toDataURL("image/png")
obj.setSrc(bar, function(img) {
obj.setSrc(bar, function (img) {
canvas.renderAll()
})
}
@@ -946,7 +995,8 @@ function regenerateQrCodesAndBarcodes(canvas, objsArray) {
}
// 清理不需要的 src 字段(保留自定义图片的 src)
function cleanupSrcFields(jsonObjects, objsArray) {
// 将 cleanupSrcFields 附加到 window 对象,确保在 ui.js 中的 saveAs 函数也能访问
window.cleanupSrcFields = function cleanupSrcFields(jsonObjects, objsArray) {
if (!jsonObjects || !Array.isArray(jsonObjects)) return;
if (!objsArray || !Array.isArray(objsArray)) return;
@@ -972,6 +1022,10 @@ function cleanupSrcFields(jsonObjects, objsArray) {
}
}
}
};
// 向后兼容
function cleanupSrcFields(jsonObjects, objsArray) {
return window.cleanupSrcFields(jsonObjects, objsArray);
}
function saveAs(op1, callback) {
@@ -990,7 +1044,7 @@ function saveAs(op1, callback) {
canvas2.remove(obj)
}
})
let j = canvas1.toJSON(['selectable', 'hoverable', 'hoverCursor', 'text', 'fontStyle', 'fontWeight', 'underline'])
let b = canvas2.toJSON(['selectable', 'hoverable', 'hoverCursor', 'text', 'fontStyle', 'fontWeight', 'underline'])
@@ -1009,18 +1063,27 @@ function saveAs(op1, callback) {
dialog
.showSaveDialog({
title: language_str('saveFile'), //'保存文件'
filters: [{ name: 'Soon File Type', extensions: ['soon'] }]
filters: [{ name: 'Soon File Type', extensions: ['soon'] }],
defaultPath: openAs.name || undefined
})
.then((result) => {
if (result.filePath == '') {
return
}
if (result.filePath.substring(result.filePath.length - 5).indexOf('.') == -1) {
result.filePath += '.soon'
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'
}
result.filePath = filePath
let fs = require('fs')
con_o.soonType = 2
fs.writeFileSync(result.filePath, JSON.stringify(con_o))
fs.writeFileSync(result.filePath, JSON.stringify(con_o), 'utf8')
openAs.name = result.filePath
layer.msg(language_str('saveSucc') + openAs.name) //'保存成功至'
saveHistory()
@@ -1048,7 +1111,7 @@ function save(op1, callback) {
canvas2.remove(obj)
}
})
let j = canvas1.toJSON(['selectable', 'hoverable', 'hoverCursor', 'text', 'fontStyle', 'fontWeight', 'underline'])
let b = canvas2.toJSON(['selectable', 'hoverable', 'hoverCursor', 'text', 'fontStyle', 'fontWeight', 'underline'])
@@ -1068,7 +1131,7 @@ function save(op1, callback) {
//打开的文件
let fs = require('fs')
con_o.soonType = 2
fs.writeFileSync(openAs.name, JSON.stringify(con_o))
fs.writeFileSync(openAs.name, JSON.stringify(con_o), 'utf8')
layer.msg(language_str('saveSucc') + openAs.name) //'保存成功至'
saveHistory()
if (callback && typeof callback === 'function') {
@@ -1079,18 +1142,27 @@ function save(op1, callback) {
dialog
.showSaveDialog({
title: language_str('saveFile'), //'保存文件'
filters: [{ name: 'Soon File Type', extensions: ['soon'] }]
filters: [{ name: 'Soon File Type', extensions: ['soon'] }],
defaultPath: openAs.name || undefined
})
.then((result) => {
if (result.filePath == '') {
return
}
if (result.filePath.substring(result.filePath.length - 5).indexOf('.') == -1) {
result.filePath += '.soon'
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'
}
result.filePath = filePath
let fs = require('fs')
con_o.soonType = 2
fs.writeFileSync(result.filePath, JSON.stringify(con_o))
fs.writeFileSync(result.filePath, JSON.stringify(con_o), 'utf8')
openAs.name = result.filePath
layer.msg(language_str('saveSucc') + openAs.name) //'保存成功至'
saveHistory()
@@ -1102,7 +1174,8 @@ function save(op1, callback) {
})
}
function saveHistory() {
// 将 saveHistory 附加到 window 对象,确保在 ui.js 中也能访问
window.saveHistory = function saveHistory() {
let fs = require('fs')
let j = {}
try {
@@ -1111,19 +1184,24 @@ function saveHistory() {
for (let item of j.history) {
if (item.path == openAs.name) {
item.time = getDate()
fs.writeFileSync(fullPath, JSON.stringify(j))
fs.writeFileSync(fullPath, JSON.stringify(j), 'utf8')
return
}
}
j.history.push({ time: getDate(), path: openAs.name })
fs.writeFileSync(fullPath, JSON.stringify(j))
fs.writeFileSync(fullPath, JSON.stringify(j), 'utf8')
} catch (e) {
let j = { history: { time: getDate(), path: openAs.name } }
fs.writeFileSync(fullPath, JSON.stringify(j))
fs.writeFileSync(fullPath, JSON.stringify(j), 'utf8')
}
};
// 向后兼容
function saveHistory() {
return window.saveHistory();
}
function open(file) {
// 使用 window.openFile 避免与浏览器原生的 window.open 冲突
window.openFile = function open(file) {
let fs = require('fs')
var fsData = fs.readFileSync(file)
openAs.name = file
@@ -1147,34 +1225,38 @@ function open(file) {
if (j.b.objects[0] && !j.b.objects[0].src) {
j.b.objects[0].src = './public/images/bg_back_2.png'
}
// 为二维码和条形码对象创建临时的 src(Fabric.js 需要 src 来创建 Image 对象)
// 加载完成后会重新生成,所以这里只需要一个占位符
const fo = j.fo || []
const bo = j.bo || []
const placeholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
// 为正面二维码和条形码创建临时 src
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
}
})
// 为背面二维码和条形码创建临时 src
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
}
})
// 加载 JSON,并在回调中重新生成二维码和条形码
canvas1.loadFromJSON(j.f, function() {
regenerateQrCodesAndBarcodes(canvas1, fo)
canvas1.loadFromJSON(j.f, function () {
if (typeof window.regenerateQrCodesAndBarcodes === 'function') {
window.regenerateQrCodesAndBarcodes(canvas1, fo);
}
canvas1.renderAll()
})
canvas2.loadFromJSON(j.b, function() {
regenerateQrCodesAndBarcodes(canvas2, bo)
canvas2.loadFromJSON(j.b, function () {
if (typeof window.regenerateQrCodesAndBarcodes === 'function') {
window.regenerateQrCodesAndBarcodes(canvas2, bo);
}
canvas2.renderAll()
})
background_image1 = canvas1.getObjects()[0]
@@ -1203,10 +1285,22 @@ function open(file) {
}
canvas1.renderAll()
canvas2.renderAll()
updateList() /*
修复打开新文件后无法撤销的bug
2022-07-16
*/
// 调用 updateList,现在它已附加到 window 对象
if (typeof window.updateList === 'function') {
window.updateList(); /*
修复打开新文件后无法撤销的bug
2022-07-16
*/
} else {
// 延迟检查,确保 core.js 已加载
setTimeout(() => {
if (typeof window.updateList === 'function') {
window.updateList();
} else {
console.error('[open函数] ❌ updateList 函数未定义!');
}
}, 100);
}
setTimeout(() => {
recordObjs1.push(JSON.stringify(objs1))
let j1 = canvas1.toJSON(['selectable', 'hoverable', 'hoverCursor', 'text', 'fontStyle', 'fontWeight', 'underline'])
@@ -1257,7 +1351,22 @@ function clearAll() {
openAs.name = ''
canvas1.renderAll()
canvas2.renderAll()
updateList()
// 调用 updateList,现在它已附加到 window 对象
if (typeof window.updateList === 'function') {
window.updateList();
} else {
// 延迟检查,确保 core.js 已加载
setTimeout(() => {
if (typeof window.updateList === 'function') {
window.updateList();
} else {
console.error('[clearAll] ❌ updateList 函数未定义!');
}
}, 100);
}
console.log()
}
// 将 clearAll 附加到 window 对象,确保全局可访问
window.clearAll = clearAll;
+3470 -3273
View File
File diff suppressed because one or more lines are too long
-21
View File
@@ -1,21 +0,0 @@
Example:
nvm install v0.10.32 Install a specific version number
nvm use 0.10 Use the latest available 0.10.x release
nvm run 0.10.32 app.js Run app.js using node v0.10.32
nvm exec 0.10.32 node app.js Run `node app.js` with the PATH pointing to node v0.10.32
nvm alias default 0.10.32 Set default node version on a shell
Note:
to remove, delete, or uninstall nvm - just remove the `$NVM_DIR` folder (usually `~/.nvm`)
Xupnei:~ xuwenwei$ nvm install v16.5.0
Version 'v16.5.0' not found - try `nvm ls-remote` to browse available versions.
Xupnei:~ xuwenwei$
Xupnei:~ xuwenwei$ nvm install v16.5.0
Downloading and installing node v16.5.0...
Downloading https://nodejs.org/dist/v16.5.0/node-v16.5.0-darwin-arm64.tar.gz...
######################################################################### 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v16.5.0 (npm v7.19.1)
-21
View File
@@ -1,21 +0,0 @@
Example:
nvm install v0.10.32 Install a specific version number
nvm use 0.10 Use the latest available 0.10.x release
nvm run 0.10.32 app.js Run app.js using node v0.10.32
nvm exec 0.10.32 node app.js Run `node app.js` with the PATH pointing to node v0.10.32
nvm alias default 0.10.32 Set default node version on a shell
Note:
to remove, delete, or uninstall nvm - just remove the `$NVM_DIR` folder (usually `~/.nvm`)
Xupnei:~ xuwenwei$ nvm install v16.5.0
Version 'v16.5.0' not found - try `nvm ls-remote` to browse available versions.
Xupnei:~ xuwenwei$
Xupnei:~ xuwenwei$ nvm install v16.5.0
Downloading and installing node v16.5.0...
Downloading https://nodejs.org/dist/v16.5.0/node-v16.5.0-darwin-arm64.tar.gz...
######################################################################### 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v16.5.0 (npm v7.19.1)
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+28
View File
@@ -0,0 +1,28 @@
{
"description": "模块文件名映射配置 - 用于加密后重命名文件",
"version": "1.0.0",
"mappings": {
"design1": {
"core": "core1",
"output": "output1",
"ui": "ui1"
},
"design2": {
"core": "core2",
"output": "output2",
"ui": "ui2"
},
"main": {
"index": "index1",
"design1": "design11",
"design2": "design22"
}
},
"notes": [
"修改此文件中的映射值可以重命名加密后的文件",
"例如:将 'core' 改为 'core_v2',加密后会生成 core_v2.jsc",
"修改后需要重新运行加密脚本",
"确保映射值唯一,避免冲突"
]
}