更新优化

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