Commit e654a4f1 by linjinhong

fix:修改逻辑

parent 6dfcf308
{"apiApiHost":"http://172.16.19.100:8060/api","fileApiUrl":"http://172.16.19.100:8060/upload/factory","visionUrl":"http://console.jomalls.com","configPath":"D:\\work\\electron-printer\\config\\env.json"}
\ No newline at end of file
{
"apiApiHost": "http://172.16.19.100:8060/api",
"fileApiUrl": "http://172.16.19.100:8060/upload/factory",
"visionUrl": "http://console.jomalls.com",
"configPath": "D:\\work\\electron-printer\\config\\env.json"
}
......@@ -17,8 +17,8 @@ export const pathMap = {
GC: "factory/podJomallOrderProduct/completeDelivery",
},
processTransparentBackground: {
CN: "api/factory/podJomallOrderProductCn/processTransparentBackground",
US: "api/factory/podJomallOrderProductUs/processTransparentBackground",
CN: "factory/podJomallOrderProductCn/processTransparentBackground",
US: "factory/podJomallOrderProductUs/processTransparentBackground",
},
};
......
......@@ -9,7 +9,6 @@ const {
cropImageTransparentEdges,
cropTransparentEdges,
processImages,
cropToPrintArea,
} = require("../utils/setImage");
import axios from "axios";
import { returnLogFilePath } from "../utils/log";
......@@ -165,7 +164,6 @@ export default {
if (data.code !== 200) {
return res.json(data);
}
console.log("downloadBySubOrderNumber", data);
// 转义中文
if (data.message) {
......@@ -175,7 +173,6 @@ export default {
let files = data.data || [data.message];
files = files.map((el) => ({ url: `${fileEnv}${el}` }));
console.log(175, files);
const downloadFunc =
params.device === 2 ? downloadOtherImage : downloadImage;
......@@ -483,17 +480,7 @@ export default {
res.json({ code: 500, msg: err.message });
}
},
//输入图片路径或目录
cropToPrintAreaApi: async (req, res) => {
const { inputPath, outputPath, data: params } = req.body;
try {
const data = await cropToPrintArea(inputPath, outputPath, params);
res.json({ code: 200, msg: data });
} catch (err) {
res.json({ code: 500, msg: err.message });
}
},
//删除图片
cleanDirectorySync: async (req, res) => {
const desktopDevice = getCurrentDesktopDevice();
......@@ -590,17 +577,30 @@ export default {
processTransparentBackground: async (req, res) => {
env = getHostApi().apiApiHost;
const token = req.headers["jwt-token"];
const params = req.body;
const { imgUrl, subOrderNumber, orderType } = req.body;
const processTransparentBackground =
pathMap["processTransparentBackground"];
let url = processTransparentBackground[params.orderType];
let postData = { url: "", subOrderNumber: "" };
let url = processTransparentBackground[orderType];
let postData = { url: imgUrl, subOrderNumber };
try {
let { data } = await axios.post(`${env}/${url}`, postData, {
let { data } = await axios.get(`${env}/${url}`, {
params: postData,
headers: { "jwt-token": token },
});
res.send(data);
console.log("processTransparentBackground", data);
if (data.message) {
data.message = encodeURIComponent(data.message);
}
let files = data.data || [data.message];
files = files.map((el) => ({ url: `${fileEnv}${el}` }));
console.log("processTransparentBackground,files", files);
const result = await downloadImage(files);
res.json({ code: 200, data: result });
} catch (err) {
console.log(err);
res.json({ code: 500, msg: err });
......
......@@ -39,8 +39,7 @@ router.post("/imageTransparentEdges", fn.imageTransparentEdges);
router.post("/imageListTransparentEdges", fn.imageListTransparentEdges);
// 处理图片并输出结果
router.post("/processImage", fn.processImage);
// 处理图片并输出结果
router.post("/cropToPrintArea", fn.cropToPrintAreaApi);
// 删除图片
router.post("/cleanDirectorySync", fn.cleanDirectorySync);
......
......@@ -562,93 +562,10 @@ async function checkImageOutsideGrid() {
}
}
const FIXED_MASK_RATIO = {
left: 0.341,
top: 0.308,
width: 0.443,
height: 0.443,
};
async function cropToPrintArea(inputPath, outputPath, data) {
let RATIO;
if (!data) return false;
// -------- 你原来的解构(我修正 drawImage 来源)--------
const { canvasWidth, canvasHeight, rect_info, drawImage } = data;
const [dx, dy, imgRenderW, imgRenderH] = drawImage;
// -------- 【关键】你原来的逻辑:有 rect_info 就覆盖比例 --------
if (rect_info) {
RATIO = {
left: rect_info.leftDistance / canvasWidth, // ✅ 转成比例
top: rect_info.topDistance / canvasHeight, // ✅ 转成比例
width: rect_info.rectWidth / canvasWidth, // ✅ 比例
height: rect_info.rectHeight / canvasHeight, // ✅ 比例
};
}
console.log("✅ 正确比例:", RATIO);
try {
// 1. 获取图片宽高
const meta = await sharp(inputPath).metadata();
const width = meta.width;
const height = meta.height;
// 2. 按比例计算(你原来的写法,完全不变)
const cropLeft = Math.round(width * RATIO.left);
const cropTop = Math.round(height * RATIO.top);
const cropWidth = Math.round(width * RATIO.width);
const cropHeight = Math.round(height * RATIO.height);
// 安全边界
const safeLeft = Math.max(0, cropLeft);
const safeTop = Math.max(0, cropTop);
const safeWidth = Math.min(cropWidth, width - safeLeft);
const safeHeight = Math.min(cropHeight, height - safeTop);
// 3. 执行裁剪(你原来的逻辑不变)
await sharp(inputPath)
.extract({
left: safeLeft,
top: safeTop,
width: safeWidth,
height: safeHeight,
})
.toFile(outputPath);
// 4. 返回你要的结构(完全不变)
const results = [
{
file: path.basename(inputPath),
status: "cropped",
outputPath: outputPath,
originalSize: { width, height },
newSize: { width: safeWidth, height: safeHeight },
cropArea: {
x: safeLeft,
y: safeTop,
width: safeWidth,
height: safeHeight,
},
},
];
fs.unlinkSync(inputPath);
return results;
} catch (error) {
throw new Error("图片裁剪失败: " + error.message);
}
}
// 分区边界检测实现
module.exports = {
cropTransparentEdges,
cropImageTransparentEdges,
processImages,
cropImage,
checkImageOutsideGrid,
cropToPrintArea,
};
......@@ -197,6 +197,10 @@ module.exports = {
store.set("desktoBoard", version);
},
getBoard: () => store.get("desktoBoard") || 3,
setIsOver: (value) => {
store.set("isOver", value);
},
getIsOver: () => store.get("isOver") || false,
setLocation: (version, locationKey) => {
if (!locationKey) return;
......
......@@ -244,6 +244,37 @@ export function extractValue(str) {
if (str.includes("_B_")) return "B";
}
export function getImgTitle(imageResList) {
return imageResList
.map((el, index) => {
el.designId = el.designId || index;
el.title = extractValue(el.designId);
return el;
})
.sort((a, b) => {
const titleA = a.title;
const titleB = b.title;
// 检查是否为空值(null、undefined、空字符串)
const isEmptyA = titleA === null || titleA === undefined || titleA === "";
const isEmptyB = titleB === null || titleB === undefined || titleB === "";
// 处理空值情况(空值排在最后)
if (isEmptyA && isEmptyB) return 0; // 两个都为空,保持原顺序
if (isEmptyA) return 1; // A为空,B不为空,A排在后面
if (isEmptyB) return -1; // B为空,A不为空,B排在后面
// 处理非空值比较(不区分大小写)
const valueA = typeof titleA === "string" ? titleA.toUpperCase() : titleA;
const valueB = typeof titleB === "string" ? titleB.toUpperCase() : titleB;
// 升序比较(A-Z)
if (valueA < valueB) return -1;
if (valueA > valueB) return 1;
return 0;
});
}
export function newMmToPxFn(mm) {
const px = (Number(mm) / 25.4) * 42;
return Number(px.toFixed(1));
......
......@@ -11,7 +11,7 @@ import pkg from "../../../../package.json";
import UpdateDialog from "@/views/design/updateDialog.vue";
import path from "path"; // 引入 path 模块
import axios from "axios";
import { extractValue } from "@/utils/index.js";
import { getImgTitle } from "@/utils/index.js";
const uuid = require("uuid");
import { mapState } from "vuex";
......@@ -169,12 +169,6 @@ export default {
imgList: {
//监听当前网格内数据,并把power设置为true
handler(value) {
const isOver = this.$dataStore.get("isOver");
console.log("isOver", isOver);
if (!isOver) {
this.$dataStore.set("isOver", false);
return;
}
if (this.detail && value?.length && this.desktopDevice === 3) {
const item = this.detail?.saveImgList?.find(
(el) => el.fileName == value[0].fileName,
......@@ -331,13 +325,13 @@ export default {
})
.then((res) => {
// console.log("item", item);
const canvasWidth = 524.0493037260068;
const canvasHeight = 589.5;
var url = URL.createObjectURL(res.data);
let img = new Image();
img.crossorigin = "";
img.src = url;
img.style.width = item.img_width + "px";
img.style.height = item.img_height + "px";
img.onerror = function() {
reject();
};
......@@ -349,7 +343,27 @@ export default {
ctx.imageSmoothingQuality = "high";
ctx.drawImage(img, ...item.drawImage);
URL.revokeObjectURL(url);
resolve();
const originWidth = img.width;
const originHeight = img.height;
const [dx, dy, drawW] = item.drawImage;
const scale = drawW / originWidth;
// 2. 黄点在【原始高清图】上的裁切坐标
const cropArea = {
left: Math.round(-dx / scale),
top: Math.round(-dy / scale),
width: Math.round(canvasWidth / scale),
height: Math.round(canvasHeight / scale),
};
// 3. 黄点相对【整个原始素材】的比例(0~1,你要的最终结果)
const maskRatio = {
left: Number((cropArea.left / originWidth).toFixed(4)),
top: Number((cropArea.top / originHeight).toFixed(4)),
width: Number((cropArea.width / originWidth).toFixed(4)),
height: Number((cropArea.height / originHeight).toFixed(4)),
};
console.log(392, maskRatio);
resolve(maskRatio);
};
})
.catch((e) => {
......@@ -377,7 +391,12 @@ export default {
// 遍历每个canvas配置项,串行处理(保持原逻辑,若想并行可改成Promise.all(canvasList.map(...)))
for (const canvasConfig of canvasList) {
// 解构赋值,简化后续取值,同时校验核心属性
const { canvasWidth, canvasHeight, list: drawItems } = canvasConfig;
const {
canvasWidth,
canvasHeight,
rect_info,
list: drawItems,
} = canvasConfig;
if (!canvasWidth || !canvasHeight || !Array.isArray(drawItems)) {
throw new Error(
"canvas配置项必须包含canvasWidth/canvasHeight/list(数组)属性",
......@@ -392,7 +411,7 @@ export default {
// 批量执行绘制方法,收集异步绘制Promise(语义化变量名,替代原模糊的list)
const drawPromises = drawItems.map((drawItem) =>
this.drawImage(canvas, drawItem),
this.drawImage(canvas, drawItem, { rect_info }),
);
// 等待当前canvas的所有绘制操作完成
await Promise.all(drawPromises);
......@@ -431,67 +450,50 @@ export default {
},
async hasDesignImagesCanvasJsonList(designImagesCanvasJsonList, bool) {
let isCustom = false;
let params;
let imageResList = [];
let urlList = [];
console.log(this.desktopDevice);
// 当adjustable有值时 直接赋值宽高
// if (
// !this.checked &&
// this.detail.diyId &&
// this.detail.adjustable &&
// designImagesCanvasJsonList &&
// this.desktopDevice !== 3
// ) {
// designImagesCanvasJsonList = JSON.parse(designImagesCanvasJsonList);
// if (!designImagesCanvasJsonList[0].images) {
// this.detail.isCustom = true;
// let imageList = await this.canvasToImage(designImagesCanvasJsonList);
// let fm = new FormData();
// for (let img of imageList) {
// let filename = uuid.v4().replace("-", "") + ".png";
// fm.append("files", this.base64ToFile(img, filename));
// }
// // console.log("fm", fm);
// let Sres = await this.$api.post("/saveToPng", fm);
// Sres.data.forEach((item, i) => {
// item.title = designImagesCanvasJsonList[i].options.title;
// item.productionFile = item.url;
// item.designId = item.designId || i.toString();
// });
// imageResList = Sres.data;
// console.log("imageResList", imageResList);
// } else {
// // designImagesCanvasJsonList.forEach((el) => {
// // el.images.forEach((item) => {
// // imageResList.push({
// // productionFile: item,
// // title: el.title,
// // });
// // });
// // });
// // for (let item of imageResList) {
// // item.productionFile = await this.saveImgByUrl(item.productionFile);
// // }
// }
// }
if (this.desktopDevice !== 3) {
// 当adjustable有值时 直接赋值宽高
if (
!this.checked &&
this.detail.diyId &&
this.detail.adjustable &&
designImagesCanvasJsonList &&
this.desktopDevice !== 3
) {
designImagesCanvasJsonList = JSON.parse(designImagesCanvasJsonList);
isCustom = !designImagesCanvasJsonList[0].images || false;
if (isCustom) {
const {
canvasWidth,
canvasHeight,
rect_info,
list,
} = designImagesCanvasJsonList[0];
const { drawImage } = list[0];
params = { canvasWidth, canvasHeight, rect_info, drawImage };
if (!designImagesCanvasJsonList[0].images) {
this.detail.isCustom = true;
let imageList = await this.canvasToImage(designImagesCanvasJsonList);
let fm = new FormData();
for (let img of imageList) {
let filename = uuid.v4().replace("-", "") + ".png";
fm.append("files", this.base64ToFile(img, filename));
}
// console.log("fm", fm);
let Sres = await this.$api.post("/saveToPng", fm);
Sres.data.forEach((item, i) => {
item.title = designImagesCanvasJsonList[i].options.title;
item.productionFile = item.url;
item.designId = item.designId || i.toString();
});
imageResList = Sres.data;
console.log("imageResList", imageResList);
} else {
// designImagesCanvasJsonList.forEach((el) => {
// el.images.forEach((item) => {
// imageResList.push({
// productionFile: item,
// title: el.title,
// });
// });
// });
// for (let item of imageResList) {
// item.productionFile = await this.saveImgByUrl(item.productionFile);
// }
}
}
// 根据生产单号查找 素材图片 下载到本地 然后返回本地地址去显示
if (!imageResList.length && !bool) {
let newType = this.orderType;
......@@ -517,8 +519,7 @@ export default {
imageResList = this.detail?.saveImgList || [];
console.log("imageResList", imageResList);
}
if (isCustom && this.desktopDevice !== 3)
imageResList = await this.cutImgFn(imageResList, true, params);
if (this.checked) {
imageResList = await this.cutImgFn(imageResList);
imageResList.forEach((el) => {
......@@ -540,38 +541,7 @@ export default {
}, 500);
}
} else {
const newImgList = imageResList
.map((el, index) => {
el.designId = el.designId || index;
el.title = extractValue(el.designId);
return el;
})
.sort((a, b) => {
const titleA = a.title;
const titleB = b.title;
// 检查是否为空值(null、undefined、空字符串)
const isEmptyA =
titleA === null || titleA === undefined || titleA === "";
const isEmptyB =
titleB === null || titleB === undefined || titleB === "";
// 处理空值情况(空值排在最后)
if (isEmptyA && isEmptyB) return 0; // 两个都为空,保持原顺序
if (isEmptyA) return 1; // A为空,B不为空,A排在后面
if (isEmptyB) return -1; // B为空,A不为空,B排在后面
// 处理非空值比较(不区分大小写)
const valueA =
typeof titleA === "string" ? titleA.toUpperCase() : titleA;
const valueB =
typeof titleB === "string" ? titleB.toUpperCase() : titleB;
// 升序比较(A-Z)
if (valueA < valueB) return -1;
if (valueA > valueB) return 1;
return 0;
});
const newImgList = getImgTitle(imageResList);
let obj = {
type: "sendFile",
value: [...newImgList],
......@@ -852,7 +822,7 @@ export default {
this.$store.commit("setGrid");
this.command(0);
},
async cutImgFn(arr, type, data) {
async cutImgFn(arr) {
if (!arr.length) return arr;
console.log(arr);
......@@ -866,11 +836,9 @@ export default {
const params = {
inputPath: el.productionFile,
outputPath: outputPath,
data,
};
let res;
if (!type) res = await this.$api.post("/processImage", params);
else res = await this.$api.post("/cropToPrintArea", params);
res = await this.$api.post("/processImage", params);
return {
fileName: outputFileName,
......
......@@ -229,13 +229,12 @@ export default {
isMove: false,
isOver: false,
dialogVisible: false,
isForcedProduction: false,
};
},
watch: {
imgList: {
async handler() {
this.isMove = false;
this.$store.commit("changeImgList", this.imgList);
},
deep: true,
......@@ -375,14 +374,6 @@ export default {
},
immediate: true,
},
// isOver: {
// handler(newValue) {
// this.dialogVisible = true;
// // if (newValue && this.newDesktopDevice == 3) {
// // this.dialogVisible = true;
// // }
// },
// },
},
methods: {
// 重构为可手动触发的方法
......@@ -655,17 +646,12 @@ export default {
this.showImgSetting = false;
},
dragStop(data, item) {
this.isMove = true;
console.log("dragStop");
this.$set(item, "y", data.y);
this.$set(item, "x", data.x);
this.imgHistoryList.push(JSON.parse(JSON.stringify(this.imgList)));
this.getCutArea();
},
resizeStop(data, item) {
this.isMove = true;
console.log("resizeStop");
if (this.selectIndex < 0 && this.imgList.length) this.selectIndex = 0;
this.$set(item, "y", data.y);
this.$set(item, "w", data.w);
......@@ -680,13 +666,10 @@ export default {
},
resizing() {},
rotating(data, item) {
this.isMove = true;
this.$set(item, "r", data.angle);
this.imgHistoryList.push(JSON.parse(JSON.stringify(this.imgList)));
},
outsideClick(e) {
console.log(e);
if (
!(
e.target.className.includes("drr") ||
......@@ -758,34 +741,24 @@ export default {
);
return img?.productionFile;
},
getBackFile({ files, size }, callback, urlList) {
console.log("productMark", this.detail);
getBackFile({ files, size }, callback, imgType) {
const isCp = this.productMark == "custom_part" ? true : false;
let that = this;
let bw = document.getElementById("line");
let bh = bw.clientHeight;
bw = bw.clientWidth;
this.isView = false;
// bw = Number(bw.replsace("px", ""));
this.isMove = false;
for (let i = 0; i < files.length; i++) {
files[i].url = files[i]?.productionFile || files[i].url;
that.$nextTick(async () => {
let w = bw / 2;
// let h = bh / 2;
let h = bh / 2;
let width_px, height_px, rate, x, y;
let data = await that.getImageSize(files[i].url);
if (size && !files[i].isCut) {
console.log("size", size);
console.log("data", data);
// if (this.newDesktopDevice == 3) {
// const scale = bh / data.height;
// width_px = data.width * scale;
// height_px = data.height * scale;
// x = (bw - data.w) / 2;
// y = h;
// rate = height_px / width_px;
// } else {
const isCut = files[i].isCut;
if (size && !isCut) {
if (isCp) {
width_px =
this.newDesktopDevice == 3
......@@ -804,10 +777,17 @@ export default {
y = height_px / 2;
rate = height_px / width_px;
// }
if (this.newDesktopDevice == 3 && imgType) {
const scale = bh / data.height;
width_px = data.width * scale;
height_px = data.height * scale;
x = (bw - data.w) / 2;
y = h;
rate = height_px / width_px;
}
} else {
rate = data.height / data.width;
console.log("data", data);
console.log("rate", rate);
if (rate > 1) {
height_px = bh * (7.5 / 10);
......@@ -834,40 +814,28 @@ export default {
h: height_px,
r: 0,
});
console.log(that.imgList);
that.selectIndex = that.imgList.length - 1;
that.showImgSetting = true;
// if (this.newDesktopDevice != 3) {
// that.ev("cover");
isCp ? that.ev("x_center") : that.ev("cover");
// }
isCp
? imgType == true
? that.ev("cover")
: that.ev("x_center")
: that.ev("cover");
if (isCut) that.ev("cover");
this.$nextTick(async () => {
const {
isImageBiggerThanGrid,
hasOutsideValidPixel,
} = await checkImageOutsideGrid();
this.isOver = hasOutsideValidPixel;
console.log("urlList", urlList);
console.log("orderType", this.orderType);
if (urlList.length == 1) {
if (isImageBiggerThanGrid && !hasOutsideValidPixel) {
let res = await this.$api.post(
pathMap["processTransparentBackground"][this.orderType],
{
url: urlList[0],
subOrderNumber: this.detail.factorySubOrderNumber,
orderType: this.orderType,
},
);
console.log("processTransparentBackground", res);
}
}
// if (this.isOver) this.$dataStore.set("isOver", this.isOver);
if (isImageBiggerThanGrid && hasOutsideValidPixel) {
this.isOver = hasOutsideValidPixel;
} else if (!isImageBiggerThanGrid) {
this.isOver = isImageBiggerThanGrid;
}
});
if (i === files.length - 1) {
callback && callback();
}
......@@ -993,13 +961,10 @@ export default {
}
this.checkList = JSON.parse(JSON.stringify(this.selectImgList));
try {
// console.log("checkList", this.checkList);
const processQueue = await Promise.all(
this.checkList.map(async (el) => {
try {
const outputDir = path.dirname(el.productionFile);
// console.log(outputDir);
const outputFileName = `${uuid.v4()}.png`;
const outputPath = path.join(outputDir, outputFileName);
......@@ -1123,7 +1088,7 @@ export default {
this.getCutArea();
},
getCutArea() {
// 语法:inset(<top> <right> <bottom> <left>)
this.isMove = true;
if (!this.drrDom) return;
let gradient = "none";
......@@ -1312,7 +1277,7 @@ export default {
this.systemSetting = this.$dataStore.get("setting");
bus.$on("busEmit", (v) => {
let { type, value, size, productMark, urls } = v;
let { type, value, size, productMark, urls, imgeType } = v;
switch (type) {
case "completeMessage":
......@@ -1363,7 +1328,7 @@ export default {
this.imgList = [];
this.selectImgList = [];
this.selectIndex = -1;
this.productMark = productMark;
this.productMark = productMark || this.productMark;
if (value.length > 0) {
this.selectImgList = value;
......@@ -1379,9 +1344,9 @@ export default {
this.selectImgIndex = 0;
}
console.log("designImageSize", this.detail.designImageSize);
if (this.selectImgIndex != -1) {
console.log("urls", urls);
this.getBackFile(
{
files: [value[this.selectImgIndex]],
......@@ -1393,6 +1358,7 @@ export default {
);
},
urls,
imgeType,
);
}
}
......@@ -1801,16 +1767,7 @@ export default {
></div>
</div>
</vue-drag-resize-rotate>
<!-- <div style="position: relative;">
<button @click="checkOutsidePixel" class="detect-btn">
检测超出区域是否有像素
</button>
<div class="result" v-if="detectResult !== null">
检测结果:{{ detectResult ? "有" : "无" }}
</div>
</div> -->
<!-- 隐藏的Canvas(用于像素检测) -->
<canvas ref="pixelCanvas" style="display: none"></canvas>
</div>
......@@ -1846,7 +1803,7 @@ export default {
class="print-tip"
:style="{ left: isView ? '' : '22%' }"
v-if="
detail?.custom_part == 'custom_part' &&
productMark == 'custom_part' &&
selectImgList.length &&
!isOver &&
!isMove &&
......@@ -1857,11 +1814,9 @@ export default {
</div>
<div
class="print-tip"
:style="{ left: isView ? '' : '22%' }"
:style="{ left: isView ? '' : '6%' }"
v-if="
detail?.custom_part == 'custom_part' &&
selectImgList.length &&
isOver
productMark == 'custom_part' && selectImgList.length && isOver
"
>
<b style="color:red"
......@@ -1996,7 +1951,7 @@ export default {
<style lang="less" scoped>
.print-tip {
position: absolute;
bottom: 16px;
bottom: 60px;
font-size: 24px;
left: 25%;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment