550 lines
20 KiB
JavaScript
550 lines
20 KiB
JavaScript
// design1.js - 主入口文件
|
||
// 导入公共模块(不依赖jQuery的部分)
|
||
require('./common/fabric-ext.js');
|
||
|
||
// 过滤 Canvas2D willReadFrequently 警告(不影响功能,只是性能提示)
|
||
if (typeof console !== 'undefined' && console.warn) {
|
||
const originalWarn = console.warn;
|
||
console.warn = function (...args) {
|
||
const message = args.join(' ');
|
||
// 过滤掉 willReadFrequently 相关的警告
|
||
if (message.includes('willReadFrequently') || message.includes('getImageData')) {
|
||
return; // 不输出这个警告
|
||
}
|
||
originalWarn.apply(console, args);
|
||
};
|
||
}
|
||
|
||
// Electron相关导入
|
||
const remote = require('@electron/remote');
|
||
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');
|
||
const { clipboard } = require('electron');
|
||
const dpi = 600;
|
||
|
||
// 发送IPC消息
|
||
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 = "";
|
||
// 确保 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) {
|
||
APIFMS = '';
|
||
}
|
||
return APIFMS;
|
||
};
|
||
// 向后兼容
|
||
function desEncrypt(str, key = "df6a551ca43181fc485f3043bcdd2fbc") {
|
||
return window.desEncrypt(str, key);
|
||
}
|
||
|
||
// 多语言切换
|
||
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);
|
||
}
|
||
|
||
// 多语言字符串获取
|
||
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参数
|
||
window.GetFile = function GetFile() {
|
||
const params = new URLSearchParams(window.location.search);
|
||
return params;
|
||
};
|
||
// 向后兼容
|
||
function GetFile() {
|
||
return window.GetFile();
|
||
}
|
||
|
||
// 日期格式化
|
||
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);
|
||
}
|
||
|
||
// 计算两点之间的距离
|
||
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);
|
||
}
|
||
|
||
// 计算角度(相对于画布中心)
|
||
window.getDeg = function getDeg(pointer, canvas) {
|
||
var centerX = canvas.width / 2;
|
||
var centerY = canvas.height / 2;
|
||
var mouseX = pointer.x;
|
||
var mouseY = pointer.y;
|
||
var dx = mouseX - centerX;
|
||
var dy = mouseY - centerY;
|
||
var angleRad = Math.atan2(dy, dx);
|
||
var angleDeg = angleRad * (180 / Math.PI);
|
||
if (angleDeg < 0) {
|
||
angleDeg += 360;
|
||
}
|
||
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) {
|
||
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) {
|
||
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) {
|
||
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) {
|
||
return window.getType(target, canvas, objs);
|
||
}
|
||
|
||
// 获取坐标的最小X值
|
||
window.getCoordsMinX = function getCoordsMinX(acoords) {
|
||
let x = acoords[0].x;
|
||
for (let item of acoords) {
|
||
if (item.x < x) {
|
||
x = item.x;
|
||
}
|
||
}
|
||
return x;
|
||
};
|
||
// 向后兼容
|
||
function getCoordsMinX(acoords) {
|
||
return window.getCoordsMinX(acoords);
|
||
}
|
||
|
||
// 获取坐标的最大X值
|
||
window.getCoordsMaxX = function getCoordsMaxX(acoords) {
|
||
let x = acoords[0].x;
|
||
for (let item of acoords) {
|
||
if (item.x > x) {
|
||
x = item.x;
|
||
}
|
||
}
|
||
return x;
|
||
};
|
||
// 向后兼容
|
||
function getCoordsMaxX(acoords) {
|
||
return window.getCoordsMaxX(acoords);
|
||
}
|
||
|
||
// 获取坐标的最小Y值
|
||
window.getCoordsMinY = function getCoordsMinY(acoords) {
|
||
let y = acoords[0].y;
|
||
for (let item of acoords) {
|
||
if (item.y < y) {
|
||
y = item.y;
|
||
}
|
||
}
|
||
return y;
|
||
};
|
||
// 向后兼容
|
||
function getCoordsMinY(acoords) {
|
||
return window.getCoordsMinY(acoords);
|
||
}
|
||
|
||
// 获取坐标的最大Y值
|
||
window.getCoordsMaxY = function getCoordsMaxY(acoords) {
|
||
let y = acoords[0].y;
|
||
for (let item of acoords) {
|
||
if (item.y > y) {
|
||
y = item.y;
|
||
}
|
||
}
|
||
return y;
|
||
};
|
||
// 向后兼容
|
||
function getCoordsMaxY(acoords) {
|
||
return window.getCoordsMaxY(acoords);
|
||
}
|
||
|
||
// ==========================================
|
||
// 全局变量定义(所有模块共享)
|
||
// 注意:所有变量都附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
|
||
// ==========================================
|
||
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)
|
||
|
||
// 内部剪贴板
|
||
window.clipboardData = {
|
||
data: null,
|
||
offset: 10 // 粘贴位置偏移量
|
||
};
|
||
|
||
// 文件管理
|
||
window.openAs = {
|
||
_name: "",
|
||
set name(val) {
|
||
if (val == "") {
|
||
$("title").html('Soon Design');
|
||
} else {
|
||
$("title").html('Soon Design - ' + val);
|
||
}
|
||
this._name = val;
|
||
},
|
||
get name() {
|
||
return this._name
|
||
},
|
||
};
|
||
|
||
// 对象数组和历史记录
|
||
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中初始化)
|
||
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模块
|
||
const fs = require('fs');
|
||
let bytenode;
|
||
try {
|
||
bytenode = require('bytenode');
|
||
require.extensions['.dl'] = require.extensions['.jsc'];
|
||
} catch (e) {
|
||
}
|
||
|
||
const appPath = (() => { try { return remote.app.getAppPath(); } catch (e) { return __dirname || process.cwd(); } })();
|
||
|
||
// 读取模块映射配置(从 lib 目录读取,跨平台兼容)
|
||
let moduleMap = {};
|
||
try {
|
||
const moduleMapPath = path.join(appPath, 'lib', 'module-map.json');
|
||
if (fs.existsSync(moduleMapPath)) {
|
||
moduleMap = JSON.parse(fs.readFileSync(moduleMapPath, 'utf8'));
|
||
}
|
||
} catch (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);
|
||
return;
|
||
} catch (e) {
|
||
}
|
||
}
|
||
|
||
// 回退到 .js 源文件
|
||
if (fs.existsSync(jsPath)) {
|
||
try {
|
||
eval(fs.readFileSync(jsPath, 'utf8'));
|
||
} catch (e) {
|
||
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');
|
||
});
|