Commit 1a6d16c7 by linjinhong

feat:对接后端接口

parent 4fbb5e26
...@@ -4,8 +4,8 @@ import { app, protocol, BrowserWindow, globalShortcut } from "electron"; ...@@ -4,8 +4,8 @@ import { app, protocol, BrowserWindow, globalShortcut } from "electron";
import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
import { createServer } from "@/server/index.js"; import { createServer } from "@/server/index.js";
import { autoUpdater } from "electron-updater"; import { autoUpdater } from "electron-updater";
const axios = require("axios");
const createDownloadQueue = require("@/utils/download-queue"); const { createBatchDownloadQueue } = require("@/utils/download-queue");
const fs = require("fs"); const fs = require("fs");
import path from "path"; // 引入 path 模块 import path from "path"; // 引入 path 模块
...@@ -31,23 +31,32 @@ const winURL = ...@@ -31,23 +31,32 @@ const winURL =
: `file://${__dirname}/index.html`; : `file://${__dirname}/index.html`;
// 全局唯一下载队列,服务启动时初始化一次 // 全局唯一下载队列,服务启动时初始化一次
const downloadQueue = createDownloadQueue({ const downloadQueue = createBatchDownloadQueue({
concurrency: 2, concurrency: 3,
retryTimes: 2, retryTimes: 2,
// 根目录:系统下载目录/排版素材,可自行修改为固定盘符 basePath: "",
basePath: path.join(app.getPath("downloads"), "自动排版素材"), // 单文件下载成功
// 文件名规则,可自定义
fileNameRule: task => `${task.batchArrangeNum}_自动排版素材.zip`,
onSuccess: task => { onSuccess: task => {
console.log(`批次 ${task.batchArrangeNum} 下载完成`); win?.webContents.send("download:file-success", {
win.webContents.send("download:success", task.batchArrangeNum); batchArrangeNum: task.batchArrangeNum,
fileName: task.fileName
});
}, },
// 单文件下载失败
onError: (task, err) => { onError: (task, err) => {
console.error(`批次 ${task.batchArrangeNum} 下载失败:`, err.message); win?.webContents.send("download:file-error", {
win.webContents.send("download:error", {
batchArrangeNum: task.batchArrangeNum, batchArrangeNum: task.batchArrangeNum,
fileName: task.fileName,
msg: err.message msg: err.message
}); });
},
// 批次校验失败(新增:返回所有异常批次)
onBatchInvalid: invalidList => {
win?.webContents.send("download:batch-invalid", invalidList);
},
// 全部任务完成
onIdle: () => {
win?.webContents.send("download:all-finish");
} }
}); });
...@@ -504,31 +513,13 @@ async function createWindow() { ...@@ -504,31 +513,13 @@ async function createWindow() {
const { width, height } = win.getBounds(); const { width, height } = win.getBounds();
win.webContents.send("window-size", { width, height }); win.webContents.send("window-size", { width, height });
}); });
// IPC 通信
// 1. 批量添加下载任务 ipcMain.on("download:submit-batch-list", (event, list) => {
ipcMain.on("download:addTasks", (event, tasks) => { downloadQueue.addBatchList(list);
const BASE_URL = ""; event.returnValue = { code: 200, msg: "已处理" };
// 给每个任务挂载获取下载地址的方法
const taskList = tasks.map(item => ({
...item,
fetchUrl: async () => {
const params = {};
const res = await axios({
method: "get",
url: `${BASE_URL}/material/getDownloadUrl`,
params
})({
batchArrangeNum: item.batchArrangeNum
});
return res.data.downloadUrl;
}
}));
downloadQueue.addTasks(taskList);
event.returnValue = { code: 200, msg: "已加入队列" };
}); });
// 2. 查询队列运行状态 ipcMain.on("download:get-status", event => {
ipcMain.on("download:getStatus", event => {
event.returnValue = { isRunning: downloadQueue.isRunning }; event.returnValue = { isRunning: downloadQueue.isRunning };
}); });
} }
......
...@@ -44,18 +44,6 @@ ...@@ -44,18 +44,6 @@
v-html="col.render(scope.row, scope.column, scope.$index)" v-html="col.render(scope.row, scope.column, scope.$index)"
></span> ></span>
<!-- 2. tag标签 -->
<el-tag
v-else-if="col.type === 'tag'"
:type="col.getTagType ? col.getTagType(scope.row) : 'primary'"
:effect="col.tagEffect || 'light'"
size="mini"
>
{{
col.getTagText ? col.getTagText(scope.row) : scope.row[col.prop]
}}
</el-tag>
<!-- 3. 图片 --> <!-- 3. 图片 -->
<el-image <el-image
v-else-if="col.type === 'image'" v-else-if="col.type === 'image'"
...@@ -107,7 +95,7 @@ ...@@ -107,7 +95,7 @@
class="table-pagination" class="table-pagination"
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
:current-page="pageInfo.pageNum" :current-page="pageInfo.currentPage"
:page-sizes="[10, 20, 50, 100]" :page-sizes="[10, 20, 50, 100]"
:page-size="pageInfo.pageSize" :page-size="pageInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper" layout="total, sizes, prev, pager, next, jumper"
...@@ -170,12 +158,12 @@ export default { ...@@ -170,12 +158,12 @@ export default {
}, },
/** /**
* 分页信息 * 分页信息
* { pageNum: 1, pageSize: 10, total: 0 } * { currentPage: 1, pageSize: 10, total: 0 }
*/ */
pageInfo: { pageInfo: {
type: Object, type: Object,
default: () => ({ default: () => ({
pageNum: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
total: 0 total: 0
}) })
......
...@@ -34,7 +34,36 @@ export const pathMap = { ...@@ -34,7 +34,36 @@ export const pathMap = {
}, },
checkInventory: { checkInventory: {
OP: "factory/podOrderOperation/check-inventory" OP: "factory/podOrderOperation/check-inventory"
} },
//烫画
//获取生产配置
productionConfig: "api/factory/production-config",
//更新生产配置
productionConfigUpdate: "/api/factory/production-config/update",
//排版列表(分页)
productionSoftware:
"/api/factory/podOrderBatchDownload/page-production-software",
//查询该批次下的所有素材
listMaterialsByBatch:
"/api/factory/podOrderBatchDownload/list-materials-by-batch",
//重新合成排版
psReComposingDesignImages:
"/api/factory/podOrderBatchDownload/psReComposingDesignImages",
//根据批次分页查询操作单
listOperationByBatch:
"/api/factory/podOrderBatchDownload/listOperationByBatch"
};
// 操作单状态枚举
export const statusMap = {
待排单: "PENDING_SCHEDULE",
待拣胚: "PENDING_PICK",
待补胚: "PENDING_REPLENISH",
生产中: "IN_PRODUCTION",
待配货: "PENDING_PACKING",
配货完成: "PACKING_COMPLETED",
已完成: "COMPLETED",
已取消: "CANCELLED",
已归档: "ARCHIVE"
}; };
export function autoRegisterRouter(router, funcKey, handler) { export function autoRegisterRouter(router, funcKey, handler) {
......
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
copySingleImage, copySingleImage,
createBatchFolder createBatchFolder
} from "@/server/utils"; } from "@/server/utils";
const { downloadPngList } = require("@/utils/download-queue");
const { const {
cropImageTransparentEdges, cropImageTransparentEdges,
cropTransparentEdges, cropTransparentEdges,
...@@ -668,12 +668,119 @@ export default { ...@@ -668,12 +668,119 @@ export default {
}, },
downloadMaterial: async (req, res) => { downloadMaterial: async (req, res) => {
try { try {
const { downloadDir, isArray, basePath } = req.body; const { urls, targetPath } = req.body;
const data = await downloadPngList(urls, targetPath);
res.send(); res.send(data);
} catch (error) { } catch (error) {
console.log("downloadMaterial", error); console.log("downloadMaterial", error);
res.json({ code: 500, msg: error }); res.json({ code: 500, msg: error });
} }
},
//获取生产配置
productionConfig: async (req, res) => {
env = getHostApi().apiApiHost;
const token = req.headers["jwt-token"];
let url = pathMap["productionConfig"];
try {
let { data } = await axios.get(`${env}/${url}`, {
headers: { "jwt-token": token }
});
res.send(data);
} catch (error) {
console.log("checkInventory", error);
res.json({ code: 500, msg: error });
}
},
//更新生产配置
productionConfigUpdate: async (req, res) => {
env = getHostApi().apiApiHost;
const token = req.headers["jwt-token"];
const params = req.body;
let url = pathMap["productionConfigUpdate"];
try {
let { data } = await axios.post(`${env}/${url}`, {
headers: { "jwt-token": token },
params
});
res.send(data);
} catch (error) {
console.log("checkInventory", error);
res.json({ code: 500, msg: error });
}
},
//排版列表(分页)
productionSoftware: async (req, res) => {
env = getHostApi().apiApiHost;
const token = req.headers["jwt-token"];
const params = req.body;
let url = pathMap["productionSoftware"];
try {
let { data } = await axios.post(`${env}/${url}`, {
headers: { "jwt-token": token },
params
});
res.send(data);
} catch (error) {
console.log("checkInventory", error);
res.json({ code: 500, msg: error });
}
},
//查询该批次下的所有素材
listMaterialsByBatch: async (req, res) => {
env = getHostApi().apiApiHost;
const token = req.headers["jwt-token"];
const params = req.body;
let url = pathMap["listMaterialsByBatch"];
try {
let { data } = await axios.get(`${env}/${url}`, {
headers: { "jwt-token": token },
params
});
res.send(data);
} catch (error) {
console.log("checkInventory", error);
res.json({ code: 500, msg: error });
}
},
//重新合成排版
psReComposingDesignImages: async (req, res) => {
env = getHostApi().apiApiHost;
const token = req.headers["jwt-token"];
const params = req.body;
let url = pathMap["psReComposingDesignImages"];
try {
let { data } = await axios.get(`${env}/${url}`, {
headers: { "jwt-token": token },
params
});
res.send(data);
} catch (error) {
console.log("checkInventory", error);
res.json({ code: 500, msg: error });
}
},
//根据批次分页查询操作单
listOperationByBatch: async (req, res) => {
env = getHostApi().apiApiHost;
const token = req.headers["jwt-token"];
const params = req.body;
let url = pathMap["listOperationByBatch"];
try {
let { data } = await axios.post(`${env}/${url}`, {
headers: { "jwt-token": token },
params
});
res.send(data);
} catch (error) {
console.log("checkInventory", error);
res.json({ code: 500, msg: error });
}
} }
}; };
...@@ -60,6 +60,19 @@ router.post("/downloadMaterial", fn.downloadMaterial); ...@@ -60,6 +60,19 @@ router.post("/downloadMaterial", fn.downloadMaterial);
//复制文件夹下文件 //复制文件夹下文件
router.post("/copySingleImageFn", fn.copySingleImageFn); router.post("/copySingleImageFn", fn.copySingleImageFn);
//获取生产配置
router.post("/productionConfig", fn.productionConfig);
//更新生产配置
router.post("/productionConfigUpdate", fn.productionConfigUpdate);
//排版列表(分页)
router.post("/productionSoftware", fn.productionSoftware);
//查询该批次下的所有素材
router.post("/productionSoftware", fn.productionSoftware);
//重新合成排版
router.post("/psReComposingDesignImages", fn.psReComposingDesignImages);
//根据批次分页查询操作单
router.post("/listOperationByBatch", fn.listOperationByBatch);
// 根据生产单号查询详情 // 根据生产单号查询详情
autoRegisterRouter(router, "findByPodProductionNo", fn.findByPodProductionNo); autoRegisterRouter(router, "findByPodProductionNo", fn.findByPodProductionNo);
......
...@@ -215,13 +215,13 @@ module.exports = { ...@@ -215,13 +215,13 @@ module.exports = {
}, },
getDTFSetting: () => getDTFSetting: () =>
store.get("DTFSetting") || { store.get("DTFSetting") || {
overWidthMode: "autoScale", widthStrategy: "1",
// 最大素材数模式:batch / custom // 最大素材数模式:batch / custom
maxPicMode: "batch", materialStrategy: "1",
// 自定义素材数量 // 自定义素材数量
customPicNum: 30, materialCount: 30,
// 自动排版规格 40+2 / 60 / none // 自动排版规格 40+2 / 60 / none
autoLayoutType: "none", autoLayoutStrategy: "3",
// 默认下载目录 // 默认下载目录
downloadDir: "" downloadDir: ""
}, },
......
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const http = require("http");
const https = require("https"); const https = require("https");
const { URL } = require("url");
const { getDTFSetting } = require("@/server/utils/store");
function createDownloadQueue(options = {}) { export function createBatchDownloadQueue(options = {}) {
// 配置项 // ========== 1. 配置项 ==========
const config = Object.assign( const config = Object.assign(
{ {
concurrency: 2, concurrency: 3,
retryTimes: 2, retryTimes: 2,
basePath: "", // 根目录,外部传入 onSuccess: () => {}, // 单文件下载成功
fileNameRule: task => `${task.batchArrangeNum}_素材.zip`, // 默认文件名规则:批次号_素材.zip onError: () => {}, // 单文件下载失败
onSuccess: () => {}, onBatchInvalid: () => {}, // 批次校验失败回调(返回异常批次列表+原因)
onError: () => {}, onIdle: () => {} // 全部任务完成
onIdle: () => {}
}, },
options options
); );
// 内部状态 // ========== 2. 内部状态 ==========
let pendingQueue = []; let pendingQueue = [];
let runningCount = 0; let runningCount = 0;
const successSet = new Set(); const successSet = new Set();
const runningSet = new Set(); const runningSet = new Set();
let isDestroyed = false; let isDestroyed = false;
// 工具方法 // ========== 3. 通用工具方法 ==========
const hasFile = targetPath => fs.existsSync(targetPath); const getRequestModule = url => {
const cleanFile = targetPath => try {
hasFile(targetPath) && fs.unlinkSync(targetPath); return new URL(url).protocol === "https:" ? https : http;
} catch (e) {
return https;
}
};
const isPngUrl = url => {
try {
const urlObj = new URL(url);
return urlObj.pathname.toLowerCase().endsWith(".png");
} catch (e) {
return false;
}
};
const getPngFileName = url => {
try {
const urlObj = new URL(url);
const name = path.basename(urlObj.pathname);
return name.toLowerCase().endsWith(".png")
? name
: `${name || `img_${Date.now()}`}.png`;
} catch (e) {
return `img_${Date.now()}.png`;
}
};
// 流式下载核心 const fileExists = targetPath => fs.existsSync(targetPath);
const cleanBadFile = targetPath =>
fileExists(targetPath) && fs.unlinkSync(targetPath);
// ========== 4. 流式下载核心 ==========
const streamDownload = (url, targetPath) => const streamDownload = (url, targetPath) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
const ws = fs.createWriteStream(targetPath); const requestModule = getRequestModule(url);
const req = https.get(url, res => { const writeStream = fs.createWriteStream(targetPath);
// 处理重定向 const request = requestModule.get(url, res => {
if ([301, 302, 307, 308].includes(res.statusCode)) { if ([301, 302, 307, 308].includes(res.statusCode)) {
ws.close(); writeStream.close();
streamDownload(res.headers.location, targetPath) streamDownload(res.headers.location, targetPath)
.then(resolve) .then(resolve)
.catch(reject); .catch(reject);
return; return;
} }
if (res.statusCode !== 200) { if (res.statusCode !== 200) {
ws.close(); writeStream.close();
cleanFile(targetPath); cleanBadFile(targetPath);
reject(new Error(`状态码 ${res.statusCode}`)); reject(new Error(`响应状态码 ${res.statusCode}`));
return; return;
} }
res.pipe(ws); res.pipe(writeStream);
}); });
ws.on("finish", () => { writeStream.on("finish", () => {
ws.close(); writeStream.close();
resolve(); resolve();
}); });
ws.on("error", err => { writeStream.on("error", err => {
ws.close(); writeStream.close();
cleanFile(targetPath); cleanBadFile(targetPath);
reject(err); reject(err);
}); });
req.on("error", err => { request.on("error", err => {
ws.close(); writeStream.close();
cleanFile(targetPath); cleanBadFile(targetPath);
reject(err); reject(err);
}); });
req.setTimeout(30000, () => { request.setTimeout(30000, () => {
req.destroy(); request.destroy();
ws.close(); writeStream.close();
cleanFile(targetPath); cleanBadFile(targetPath);
reject(new Error("下载超时")); reject(new Error("下载超时"));
}); });
}); });
// 队列消费 // ========== 5. 队列消费逻辑 ==========
const consume = () => { const consume = () => {
if (isDestroyed) return; if (isDestroyed) return;
if (runningCount >= config.concurrency || pendingQueue.length === 0) { if (runningCount >= config.concurrency || pendingQueue.length === 0) {
...@@ -85,16 +116,11 @@ function createDownloadQueue(options = {}) { ...@@ -85,16 +116,11 @@ function createDownloadQueue(options = {}) {
runningCount++; runningCount++;
(async () => { (async () => {
try { try {
// 自动创建当前批次的目录(仅创建需要下载的批次目录,不批量预创建)
const targetDir = path.dirname(task.targetPath); const targetDir = path.dirname(task.targetPath);
if (!hasFile(targetDir)) fs.mkdirSync(targetDir, { recursive: true }); if (!fileExists(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
// 获取下载地址 }
const url = await streamDownload(task.downloadUrl, task.targetPath);
typeof task.fetchUrl === "function"
? await task.fetchUrl(task)
: task.downloadUrl;
await streamDownload(url, task.targetPath);
successSet.add(task.targetPath); successSet.add(task.targetPath);
config.onSuccess(task); config.onSuccess(task);
} catch (err) { } catch (err) {
...@@ -112,36 +138,94 @@ function createDownloadQueue(options = {}) { ...@@ -112,36 +138,94 @@ function createDownloadQueue(options = {}) {
})(); })();
}; };
// 对外方法 // ========== 6. 对外暴露方法 ==========
return { return {
addTasks(tasks = []) { addBatchList(list = []) {
if (isDestroyed) return; if (isDestroyed || !Array.isArray(list)) return;
const validTasks = tasks
.map(row => {
// 按规则拼接完整路径:根目录 / 批次号:xxx / 自动排版素材 / 文件名
const dir = path.join(
config.basePath,
`批次号:${row.batchArrangeNum}`,
"自动排版素材"
);
const fileName = config.fileNameRule(row);
const targetPath = path.join(dir, fileName);
return { ...row, targetPath, remainRetry: config.retryTimes };
})
// 三重过滤:本地已存在、已下载成功、正在队列中
.filter(
task =>
!hasFile(task.targetPath) &&
!successSet.has(task.targetPath) &&
!runningSet.has(task.targetPath)
);
if (validTasks.length === 0) return; // 第一步:筛选 layoutStatus = 3 或 5 的批次
validTasks.forEach(t => { const targetBatch = list.filter(item =>
runningSet.add(t.targetPath); [3, 5].includes(item.layoutStatus)
pendingQueue.push(t); );
const invalidBatchList = []; // 收集异常批次
const fileTasks = [];
// 第二步:逐个校验批次URL合法性
targetBatch.forEach(batch => {
const batchNo = batch.batchArrangeNum || "未知批次";
// 校验1:URL 不是字符串类型
if (typeof batch.url !== "string") {
invalidBatchList.push({
batchArrangeNum: batchNo,
reason: "下载链接格式错误,非字符串类型"
});
return;
}
// 校验2:URL 为空字符串/纯空格
if (batch.url.trim() === "") {
invalidBatchList.push({
batchArrangeNum: batchNo,
reason: "下载链接为空"
});
return;
}
// 第三步:拆分多URL,过滤空值,校验PNG格式
const urlList = batch.url
.split(",")
.map(u => u.trim())
.filter(Boolean);
const validPngUrls = urlList.filter(url => isPngUrl(url));
// 校验3:拆分后无有效PNG链接
if (validPngUrls.length === 0) {
invalidBatchList.push({
batchArrangeNum: batchNo,
reason: "无有效PNG格式下载链接"
});
return;
}
// 第四步:生成合法下载任务,去重过滤
const dir = path.join(
getDTFSetting().downloadDir,
`批次号:${batchNo}`,
"自动排版素材"
);
validPngUrls.forEach(url => {
const fileName = getPngFileName(url);
const targetPath = path.join(dir, fileName);
if (
!fileExists(targetPath) &&
!successSet.has(targetPath) &&
!runningSet.has(targetPath)
) {
fileTasks.push({
batchArrangeNum: batchNo,
downloadUrl: `https://factory.jomalls.com${url}`,
targetPath,
fileName,
remainRetry: config.retryTimes
});
}
});
}); });
consume();
// 有异常批次,通过回调抛出
if (invalidBatchList.length > 0) {
config.onBatchInvalid(invalidBatchList);
}
// 启动下载队列
if (fileTasks.length > 0) {
fileTasks.forEach(task => {
runningSet.add(task.targetPath);
pendingQueue.push(task);
});
consume();
}
}, },
get isRunning() { get isRunning() {
...@@ -158,4 +242,158 @@ function createDownloadQueue(options = {}) { ...@@ -158,4 +242,158 @@ function createDownloadQueue(options = {}) {
}; };
} }
module.exports = createDownloadQueue; /**
* 批量下载PNG图片到指定文件夹
* @param {string[]} urls - PNG图片链接数组
* @param {string} targetDir - 目标文件夹绝对路径
* @param {Object} [options] - 可选配置
* @param {number} [options.concurrency=2] - 同时下载数量
* @param {number} [options.timeout=30000] - 单文件超时时间(ms)
* @param {number} [options.retryTimes=1] - 单文件失败重试次数
* @returns {Promise<{success: string[], failed: {url: string, error: string}[]}>}
*/
export function downloadPngList(urls, targetDir, options = {}) {
const config = {
concurrency: 2,
timeout: 30000,
retryTimes: 1,
...options
};
return new Promise(resolve => {
// 参数合法性校验
if (!Array.isArray(urls) || urls.length === 0) {
resolve({
success: [],
failed: [{ url: "", error: "下载链接数组为空" }]
});
return;
}
console.log(
`开始批量下载,共 ${urls.length} 个链接,目标目录:${targetDir}`
);
// 自动创建目标目录(多级递归创建,不需要可注释掉)
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
const successList = []; // 下载成功的文件路径
const failedList = []; // 下载失败的链接+原因
let currentIndex = 0; // 当前处理到第几个链接
let runningCount = 0; // 当前正在下载的数量
const total = urls.length;
// 从URL中提取PNG文件名,无后缀自动补.png
const getPngFileName = url => {
try {
const urlObj = new URL(url);
const name = path.basename(urlObj.pathname);
return name.toLowerCase().endsWith(".png") ? name : `${name}.png`;
} catch (e) {
return `img_${Date.now()}_${Math.random()
.toString(36)
.slice(2, 6)}.png`;
}
};
// 单文件流式下载核心
const streamDownload = (url, filePath) => {
return new Promise((resolve, reject) => {
const requestModule = url.startsWith("https:") ? https : http;
const writeStream = fs.createWriteStream(filePath);
const request = requestModule.get(url, res => {
// 自动处理301/302/307/308重定向
if ([301, 302, 307, 308].includes(res.statusCode)) {
writeStream.close();
streamDownload(res.headers.location, filePath)
.then(resolve)
.catch(reject);
return;
}
if (res.statusCode !== 200) {
writeStream.close();
fs.existsSync(filePath) && fs.unlinkSync(filePath);
reject(new Error(`HTTP状态码 ${res.statusCode}`));
return;
}
res.pipe(writeStream);
});
writeStream.on("finish", () => {
console.log("downloadPngList---finish");
writeStream.close();
resolve();
});
writeStream.on("error", err => {
writeStream.close();
fs.existsSync(filePath) && fs.unlinkSync(filePath);
reject(err);
});
request.on("error", err => {
writeStream.close();
fs.existsSync(filePath) && fs.unlinkSync(filePath);
reject(err);
});
// 超时兜底
request.setTimeout(config.timeout, () => {
request.destroy();
writeStream.close();
fs.existsSync(filePath) && fs.unlinkSync(filePath);
reject(new Error("下载超时"));
});
});
};
// 带重试的单任务执行
const runTask = async url => {
const fileName = getPngFileName(url);
const filePath = path.join(targetDir, fileName);
// 本地文件已存在,直接跳过
if (fs.existsSync(filePath)) {
successList.push(filePath);
return;
}
console.log(`开始下载:${fileName}`);
let remainRetry = config.retryTimes;
try {
await streamDownload(url, filePath);
console.log(`下载成功:${fileName}`);
successList.push(filePath);
} catch (err) {
if (remainRetry > 0) {
remainRetry--;
} else {
failedList.push({ url, error: err.message });
}
}
};
// 并发调度器
const next = () => {
// 并发数未满且还有未处理任务,继续启动
while (runningCount < config.concurrency && currentIndex < total) {
runningCount++;
const url = urls[currentIndex].trim();
currentIndex++;
runTask(url).finally(() => {
runningCount--;
next();
});
}
// 所有任务执行完毕,返回结果
if (runningCount === 0 && currentIndex >= total) {
console.log(
`全部任务执行完成,成功:${successList.length} 个,失败:${failedList.length} 个`
);
resolve({ success: successList, failed: failedList });
}
};
next();
});
}
<script> <script>
import { mapState } from "vuex"; const { getDTFSetting } = require("@/server/utils/store");
const { getDesktopDevice, getDTFSetting } = require("@/server/utils/store");
const { ipcRenderer } = require("electron"); const { ipcRenderer } = require("electron");
export default { export default {
...@@ -18,39 +17,13 @@ export default { ...@@ -18,39 +17,13 @@ export default {
return { return {
dialogVisible: false, dialogVisible: false,
dtfSetting: getDTFSetting(), dtfSetting: getDTFSetting(),
radio: "" radio: "",
searchForm: {}
}; };
}, },
computed: { computed: {},
...mapState([ mounted() {},
"defaultProportion", created() {},
"countryList",
"orderType",
"grid",
"imgList"
])
},
mounted() {
this.$nextTick(() => {
this.$refs.searchRef?.focus();
if (this.desktopDevice !== 3) {
this.selectGridIndex = 0;
this.setting.gridValue = 0;
} else {
this.selectGridIndex = 5;
this.setting.gridValue = 5;
}
});
this.$store.commit("changeDesktopDevice", getDesktopDevice());
},
created() {
localStorage.setItem("desktoVersion", "print");
if (this.$dataStore.get("setting")) {
this.setting = this.$dataStore.get("setting");
} else {
this.$dataStore.set("setting", this.setting);
}
},
methods: { methods: {
dropdownCommand(v) { dropdownCommand(v) {
...@@ -87,13 +60,10 @@ export default { ...@@ -87,13 +60,10 @@ export default {
goBack() { goBack() {
this.$router.push({ name: "design-dtf" }); this.$router.push({ name: "design-dtf" });
}, },
goSetting() { goSetting() {},
this.$router.push({ getDataInfo() {
path: "/DTFsetting", this.$emit("search", this.searchForm);
query: { id: 123 }
});
}, },
getDataInfo() {},
productionCompleted() { productionCompleted() {
this.$confirm("确认完成生产?", "提示", { this.$confirm("确认完成生产?", "提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
...@@ -106,13 +76,12 @@ export default { ...@@ -106,13 +76,12 @@ export default {
changeTypesetting() { changeTypesetting() {
this.dialogVisible = true; this.dialogVisible = true;
}, },
submit() { async submit() {
console.log(this.radio);
if (!this.radio) { if (!this.radio) {
return this.$message.error("请选择排版宽度"); return this.$message.error("请选择排版宽度");
} }
if (this.dtfSetting.overWidthMode === "biggerSize" && this.radio == 60) { if (this.dtfSetting.widthStrategy == 3 && this.radio == 60) {
this.$confirm( this.$confirm(
"由于排版设置中选择“按更大规格排版”仅适用于40+2,选60时,默认超60的规格不排版", "由于排版设置中选择“按更大规格排版”仅适用于40+2,选60时,默认超60的规格不排版",
"提示", "提示",
...@@ -120,13 +89,19 @@ export default { ...@@ -120,13 +89,19 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
type: "warning" type: "warning"
} }
).then(() => { );
this.dialogVisible = false; await this.$api.post("/psReComposingDesignImages", {
this.$message( batchArrangeNum: this.templateBatchArrangeNum,
"排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看" templateWidth: this.radio
);
}); });
this.$message(
"排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看"
);
} else { } else {
await this.$api.post("/psReComposingDesignImages", {
batchArrangeNum: this.templateBatchArrangeNum,
templateWidth: this.radio
});
this.$message( this.$message(
"排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看" "排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看"
); );
...@@ -161,8 +136,26 @@ export default { ...@@ -161,8 +136,26 @@ export default {
>返回</el-button >返回</el-button
></el-form-item ></el-form-item
> >
<el-form-item> <el-input></el-input></el-form-item> <el-form-item>
<el-form-item label="操作单状态"> <el-input></el-input></el-form-item> <el-input
placeholder="请扫描操作单"
v-model="searchForm.operationNo"
></el-input
></el-form-item>
<el-form-item label="操作单状态">
<el-select v-model="searchForm.status" placeholder="请选择" clearable>
<el-option
v-for="(value, label) in statusMap"
:key="value"
:label="label"
:value="value"
></el-option> </el-select
></el-form-item>
<el-form-item label="操作单排版状态">
<el-select v-model="searchForm.layout" placeholder="请选择">
<el-option label="是" :value="true"></el-option>
<el-option label="否" :value="false"> </el-option> </el-select
></el-form-item>
<el-form-item> <el-form-item>
<el-button @click="getDataInfo" type="primary" <el-button @click="getDataInfo" type="primary"
......
...@@ -18,12 +18,7 @@ export default { ...@@ -18,12 +18,7 @@ export default {
}), }),
type: Object type: Object
}, },
factoryType: { type: String, default: "CN" }, factoryType: { type: String, default: "CN" }
cardConfig: {
imageSrc: "./src/assets/template-bg-1.jpg",
title: "title",
time: "time"
}
}, },
data() { data() {
return { return {
...@@ -31,7 +26,7 @@ export default { ...@@ -31,7 +26,7 @@ export default {
detailVisible: false, detailVisible: false,
logList: [], logList: [],
pageInfo: { pageInfo: {
pageNum: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
total: 2 total: 2
}, },
...@@ -49,14 +44,14 @@ export default { ...@@ -49,14 +44,14 @@ export default {
}; };
}), }),
detailRow: { detailRow: {
name: { label: "批次号", value: 111 }, batchArrangeNumber: { label: "批次号", value: 111 },
name1: { label: "操作单数量", value: 111 }, operationNum: { label: "操作单数量", value: 111 },
name2: { label: "素材数量", value: 111 }, materialNum: { label: "素材数量", value: 111 },
name3: { label: "工艺类型", value: 111 }, craftType: { label: "工艺类型", value: 111 },
name6: { label: "规范素材", value: 111 }, standardDesignImage: { label: "规范素材", value: 111 },
name4: { label: "创建时间", value: 111 }, createTime: { label: "创建时间", value: 111 },
name5: { label: "排版状态", value: 111 }, layoutStatus: { label: "排版状态", value: 111 },
name7: { label: "操作单状态", value: 111 } status: { label: "操作单状态", value: 111 }
} }
}; };
}, },
...@@ -180,30 +175,25 @@ export default { ...@@ -180,30 +175,25 @@ export default {
{{ item.operationNo }} {{ item.operationNo }}
</span> </span>
</template> </template>
<template #top_left> <template #top_right>
<el-tooltip <el-tooltip
v-if="item.outOfStock" v-if="item.layout"
effect="light" effect="light"
content="缺货" content="排版完成"
placement="bottom" placement="bottom"
> >
<div <div
style=" style="
background-color: #f56c6c; background-color: #f0f9eb;
color: #fff; color: #fff;
padding: 2px 4px; padding: 2px 4px;
border-radius: 4px;
font-size: 12px; font-size: 12px;
" "
> >
</div> </div>
</el-tooltip> </el-tooltip>
<span v-if="item.tagsId" class="flex-row flex-row-gap6">
<el-tag v-for="tag in getItemTags(item.tagsId)" :key="tag.id">
{{ tag.name }}
</el-tag>
</span>
</template> </template>
<template #images> <template #images>
...@@ -291,9 +281,9 @@ export default { ...@@ -291,9 +281,9 @@ export default {
<div class="card-info-row full"> <div class="card-info-row full">
<span <span
class="info-value ellipsis" class="info-value ellipsis"
:title="item.productName || ''" :title="item.operationNo || ''"
> >
{{ item.productName }} {{ item.operationNo }}
</span> </span>
</div> </div>
<div class="card-info-row"> <div class="card-info-row">
......
<script> <script>
import { mapState } from "vuex";
const { getDesktopDevice } = require("@/server/utils/store");
export default { export default {
props: { props: {
user: { user: {
...@@ -13,38 +11,13 @@ export default { ...@@ -13,38 +11,13 @@ export default {
factoryType: { type: String, default: "CN" } factoryType: { type: String, default: "CN" }
}, },
data() { data() {
return {}; return {
}, searchForm: { batchArrangeNumber: "", layoutStatus: "", startTime: "" }
computed: { };
...mapState([
"defaultProportion",
"countryList",
"orderType",
"grid",
"imgList"
])
},
mounted() {
this.$nextTick(() => {
this.$refs.searchRef?.focus();
if (this.desktopDevice !== 3) {
this.selectGridIndex = 0;
this.setting.gridValue = 0;
} else {
this.selectGridIndex = 5;
this.setting.gridValue = 5;
}
});
this.$store.commit("changeDesktopDevice", getDesktopDevice());
},
created() {
localStorage.setItem("desktoVersion", "print");
if (this.$dataStore.get("setting")) {
this.setting = this.$dataStore.get("setting");
} else {
this.$dataStore.set("setting", this.setting);
}
}, },
computed: {},
mounted() {},
created() {},
methods: { methods: {
dropdownCommand(v) { dropdownCommand(v) {
...@@ -78,14 +51,7 @@ export default { ...@@ -78,14 +51,7 @@ export default {
return ""; return "";
}, },
goBack() {
// Vue路由返回
this.$router.push({
name: "design"
});
// 如果需要关闭当前弹窗/子窗口,搭配:
// ipcRenderer.send("close-current-win");
},
goSetting() { goSetting() {
this.$router.push({ this.$router.push({
name: "dtf-setting" name: "dtf-setting"
...@@ -96,7 +62,9 @@ export default { ...@@ -96,7 +62,9 @@ export default {
name: "dtf-batch-detail" name: "dtf-batch-detail"
}); });
}, },
getDataInfo() {} getDataInfo() {
this.$emit("search", this.searchForm);
}
} }
}; };
</script> </script>
...@@ -104,10 +72,39 @@ export default { ...@@ -104,10 +72,39 @@ export default {
<template> <template>
<div> <div>
<div class="page-header"> <div class="page-header">
<el-form style="display: flex;flex-wrap: nowrap;" inline> <el-form
<el-form-item label="批次号"> <el-input></el-input></el-form-item> style="display: flex;flex-wrap: nowrap;"
<el-form-item label="排版状态"> <el-input></el-input></el-form-item> inline
<el-form-item label="创建时间"> <el-input></el-input></el-form-item> :model="searchForm"
>
<el-form-item label="批次号">
<el-input
v-model="searchForm.batchArrangeNumber"
placeholder="请输入批次号"
></el-input
></el-form-item>
<el-form-item label="排版状态">
<el-select
v-model="searchForm.layoutStatus"
placeholder="请选择排版状态"
>
<el-option label="待排版" :value="1"></el-option>
<el-option label="排版中" :value="2"> </el-option>
<el-option label="排版成功" :value="3"> </el-option>
<el-option label="排版失败" :value="4"> </el-option>
<el-option label="部分成功" :value="5"> </el-option>
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="searchForm.startTime"
type="datetime"
placeholder="选择创建时间"
format="yyyy 年 MM 月 dd 日"
value-format="yyyy-MM-dd"
>
</el-date-picker
></el-form-item>
<el-form-item> <el-form-item>
<el-button @click="getDataInfo" type="primary" <el-button @click="getDataInfo" type="primary"
>查询 >查询
...@@ -118,12 +115,6 @@ export default { ...@@ -118,12 +115,6 @@ export default {
>DTF排版设置 >DTF排版设置
</el-button></el-form-item </el-button></el-form-item
> >
<el-form-item>
<el-button @click="goSetting1" type="success"
>详情页
</el-button></el-form-item
>
</el-form> </el-form>
<div class="right-user"> <div class="right-user">
......
...@@ -3,6 +3,7 @@ import BaseTable from "../../components/BaseTable.vue"; ...@@ -3,6 +3,7 @@ import BaseTable from "../../components/BaseTable.vue";
const { remote, ipcRenderer } = require("electron"); const { remote, ipcRenderer } = require("electron");
const { getDTFSetting } = require("@/server/utils/store"); const { getDTFSetting } = require("@/server/utils/store");
const { Menu } = remote; const { Menu } = remote;
const path = require("path");
import DTFhead from "./components/head.vue"; import DTFhead from "./components/head.vue";
export default { export default {
...@@ -23,30 +24,20 @@ export default { ...@@ -23,30 +24,20 @@ export default {
dialogVisible: false, dialogVisible: false,
selectionList: [], selectionList: [],
radio: "", radio: "",
templateBatchArrangeNum: "",
dtfSetting: getDTFSetting(), dtfSetting: getDTFSetting(),
pageInfo: { pageInfo: {
pageNum: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
total: 2 total: 2
}, },
tableList: Array.from({ length: 50 }, (_, index) => { tableList: [],
const isDtg = index % 2 === 0;
return {
id: index + 1,
batchArrangeNum: index + 1,
status: index % 3 === 0 ? 0 : 1,
img: isDtg ? "/static/dtg.jpg" : "/static/dtf.jpg",
subOrderNumber: index % 4 !== 0,
num: isDtg ? 120 + index * 2 : 86 + index,
failedReason: ""
};
}),
tableConfig: [ tableConfig: [
{ {
prop: "batchArrangeNum", prop: "batchArrangeNum",
label: "批次号", label: "批次号",
width: 100, width: 100,
slotName: "batchNo" slotName: "batchArrangeNum"
}, },
{ {
prop: "operationNum", prop: "operationNum",
...@@ -68,7 +59,13 @@ export default { ...@@ -68,7 +59,13 @@ export default {
prop: "standardDesignImage", prop: "standardDesignImage",
label: "规范素材", label: "规范素材",
width: 100, width: 100,
slotName: "standardDesignImage" render(row) {
return row.standardDesignImage == 0
? "否"
: row.standardDesignImage == 1
? "是"
: "混合";
}
}, },
{ {
label: "创建时间", label: "创建时间",
...@@ -77,7 +74,8 @@ export default { ...@@ -77,7 +74,8 @@ export default {
{ {
label: "排版状态", label: "排版状态",
width: 140, width: 140,
prop: "status" prop: "layoutStatus",
slotName: "layoutStatus"
}, },
{ {
prop: "failReason", prop: "failReason",
...@@ -87,7 +85,7 @@ export default { ...@@ -87,7 +85,7 @@ export default {
}, },
{ {
label: "排版参数", label: "排版参数",
prop: "layoutParameters", prop: "composingParam",
width: 300 width: 300
}, },
{ {
...@@ -95,68 +93,88 @@ export default { ...@@ -95,68 +93,88 @@ export default {
width: 260, width: 260,
slotName: "operation" slotName: "operation"
} }
] ],
layoutStatus: {
1: { label: "待排版", type: "warning" },
2: { label: "排版中", type: "info" },
3: { label: "排版成功", type: "success" },
4: { label: "排版失败", type: "danger" },
5: { label: "部分成功", type: "success" }
}
}; };
}, },
mounted() { mounted() {
this.fetchBatchList(); this.fetchBatchList();
// 开启5分钟轮询 this.pollTimer = setInterval(() => this.fetchList(), 300000);
this.pollTimer = setInterval(() => {
this.fetchBatchList();
}, 5 * 60 * 1000);
// 监听下载结果 // 单文件下载成功
ipcRenderer.on("download:success", (_, batchNum) => { ipcRenderer.on("download:file-success", (_, data) => {
this.$message.success(`批次 ${batchNum} 素材下载完成`); console.log(`批次 ${data.batchArrangeNum}${data.fileName} 下载完成`);
}); });
ipcRenderer.on("download:error", (_, { batchArrangeNum, msg }) => {
this.$message.error(`批次 ${batchArrangeNum} 下载失败:${msg}`); // 单文件下载失败
ipcRenderer.on("download:file-error", (_, data) => {
this.$message.error(
`批次 ${data.batchArrangeNum}${data.fileName} 下载失败,${data.msg}`
);
});
// 新增:批次校验失败,批量提示
ipcRenderer.on("download:batch-invalid", (_, invalidList) => {
const msg = invalidList
.map(item => `【${item.batchArrangeNum}${item.reason}`)
.join(";");
this.$message.warning(`存在异常批次:${msg}`);
}); });
}, },
beforeDestroy() { beforeDestroy() {
clearInterval(this.pollTimer); clearInterval(this.pollTimer);
ipcRenderer.removeAllListeners("download:success"); ipcRenderer.removeAllListeners("download:file-success");
ipcRenderer.removeAllListeners("download:error"); ipcRenderer.removeAllListeners("download:file-error");
ipcRenderer.removeAllListeners("download:batch-invalid");
ipcRenderer.removeAllListeners("download:all-finish");
}, },
methods: { methods: {
async fetchBatchList() { //定时任务
async fetchBatchList(value) {
// 先判断:有下载任务在跑,本轮直接跳过 // 先判断:有下载任务在跑,本轮直接跳过
const status = ipcRenderer.sendSync("download:getStatus"); const status = ipcRenderer.sendSync("download:get-status");
if (status.isRunning) return; if (status.isRunning) return;
let params = {
currentPage: this.pageInfo.currentPage,
pageSize: this.pageInfo.pageSize
};
if (value) {
params = { ...params, ...value };
}
try { try {
// const res = await getBatchListApi(); const res = await await this.$api.post("/productionSoftware", params);
let res;
if (res.code === 200) { if (res.code === 200) {
this.tableData = res.data || []; this.tableData = res.data.records || [];
this.autoHandleDownload(); this.pageInfo.total = res.data.total;
ipcRenderer.sendSync("download:submit-batch-list", this.tableData);
} }
} catch (err) { } catch (err) {
console.error("批次列表拉取失败", err); console.error("批次列表拉取失败", err);
} }
}, },
autoHandleDownload() {
// 1. 过滤出 status 为“是”的批次
const finishList = this.tableData.filter(item => item.status === "是");
if (finishList.length === 0) return;
// 2. 直接发给主进程,主进程会自动校验本地文件、过滤已存在的批次
ipcRenderer.sendSync("download:addTasks", finishList);
},
handleSelect(rows) { handleSelect(rows) {
console.log("选中行", rows); console.log("选中行", rows);
this.selectionList = rows; this.selectionList = rows;
}, },
handleSizeChange(size) { handleSizeChange(size) {
this.pageInfo.pageSize = size; this.pageInfo.pageSize = size;
this.pageInfo.pageNum = 1; this.pageInfo.currentPage = 1;
this.loadData(); this.loadData();
}, },
handleCurrentChange(page) { handleCurrentChange(page) {
this.pageInfo.pageNum = page; this.pageInfo.currentPage = page;
this.loadData(); this.loadData();
}, },
//右键选择器
openMenu(e) { openMenu(e) {
e.preventDefault(); e.preventDefault();
const template = [ const template = [
...@@ -174,12 +192,14 @@ export default { ...@@ -174,12 +192,14 @@ export default {
const menu = Menu.buildFromTemplate(template); const menu = Menu.buildFromTemplate(template);
menu.popup({ x: e.clientX, y: e.clientY }); menu.popup({ x: e.clientX, y: e.clientY });
}, },
//查看排版文件
async goFliePage(value, type) { async goFliePage(value, type) {
console.log(value); console.log(value);
let { data } = await this.$api.post("/createBatchFolder", { let { data } = await this.$api.post("/createBatchFolder", {
basePath: this.dtfSetting.downloadDir, basePath: this.dtfSetting.downloadDir,
downloadDir: value.batchNo, downloadDir: value.batchArrangeNum,
isArray: false isArray: false
}); });
console.log("goFliePage", data); console.log("goFliePage", data);
...@@ -187,22 +207,26 @@ export default { ...@@ -187,22 +207,26 @@ export default {
ipcRenderer.send("open-folder-only", data); ipcRenderer.send("open-folder-only", data);
} }
}, },
changeTypesetting() {
if (this.dtfSetting.autoLayoutType == "none") { //打开手动排版弹窗
changeTypesetting(value) {
if (this.dtfSetting.autoLayoutStrategy == 3) {
this.dialogVisible = true; this.dialogVisible = true;
this.templateBatchArrangeNum = value;
} else { } else {
this.$message( this.$message(
"排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看" "排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看"
); );
} }
}, },
submit() {
console.log(this.radio); //提交手动排版
async submit() {
if (!this.radio) { if (!this.radio) {
return this.$message.error("请选择排版宽度"); return this.$message.error("请选择排版宽度");
} }
if (this.dtfSetting.overWidthMode === "biggerSize" && this.radio == 60) { if (this.dtfSetting.widthStrategy == 3 && this.radio == 60) {
this.$confirm( this.$confirm(
"由于排版设置中选择“按更大规格排版”仅适用于40+2,选60时,默认超60的规格不排版", "由于排版设置中选择“按更大规格排版”仅适用于40+2,选60时,默认超60的规格不排版",
"提示", "提示",
...@@ -210,27 +234,56 @@ export default { ...@@ -210,27 +234,56 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
type: "warning" type: "warning"
} }
).then(() => { );
this.$message( await this.$api.post("/psReComposingDesignImages", {
"排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看" batchArrangeNum: this.templateBatchArrangeNum,
); templateWidth: this.radio
}); });
this.$message(
"排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看"
);
} else { } else {
await this.$api.post("/psReComposingDesignImages", {
batchArrangeNum: this.templateBatchArrangeNum,
templateWidth: this.radio
});
this.$message( this.$message(
"排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看" "排版进行中,请查看处理状态,排版完成的素材至文件夹排版素材查看"
); );
} }
}, },
//跳转批次详情页
toDetail(value) { toDetail(value) {
this.$router.push({ this.$router.push({
name: "dtf-batch-detail", name: "dtf-batch-detail",
params: { params: {
batchNo: value batchArrangeNum: value
} }
}); });
}, },
downloadFile() {
this.$message("下载进行中,下载完成的素材将在文件夹原素材中显示"); //下载批次原素材
async downloadFile(value) {
try {
const { data } = await this.$api.post("/listMaterialsByBatch", {
batchArrangeNum: value
});
const res = await this.$api.post("/downloadMaterial", {
urls: data.urls,
targetPath: path.join(
getDTFSetting().downloadDir,
`批次号:${value}`,
"原素材"
)
});
console.log("listMaterialsByBatch-", data);
console.log("downloadMaterial", res);
this.$message("下载进行中,下载完成的素材将在文件夹原素材中显示");
} catch (error) {
console.log(error);
}
} }
} }
}; };
...@@ -238,7 +291,11 @@ export default { ...@@ -238,7 +291,11 @@ export default {
<template> <template>
<div class="page" @contextmenu.prevent="openMenu"> <div class="page" @contextmenu.prevent="openMenu">
<DTFhead :user="user" :factoryType="factoryType"></DTFhead> <DTFhead
:user="user"
:factoryType="factoryType"
@search="fetchBatchList"
></DTFhead>
<BaseTable <BaseTable
v-if="tableList.length" v-if="tableList.length"
ref="tableRefs" ref="tableRefs"
...@@ -256,11 +313,16 @@ export default { ...@@ -256,11 +313,16 @@ export default {
size="mini" size="mini"
> >
<!-- 自定义插槽示例 --> <!-- 自定义插槽示例 -->
<template #batchNo="scope"> <template #batchArrangeNum="scope">
<a href="javascript:;" @click="toDetail(scope.row.batchNo)">{{ <a href="javascript:;" @click="toDetail(scope.row.batchArrangeNum)">{{
scope.row.batchNo scope.row.batchArrangeNum
}}</a> }}</a>
</template> </template>
<template #layoutStatus="scope">
<el-tag :type="layoutStatus[scope.row?.layoutStatus].type">{{
layoutStatus[scope.row?.layoutStatus].label
}}</el-tag>
</template>
<template #failReason="scope"> <template #failReason="scope">
<div style="white-space: pre-line"> <div style="white-space: pre-line">
<span v-html="scope.row?.failReason"></span> <span v-html="scope.row?.failReason"></span>
...@@ -272,21 +334,21 @@ export default { ...@@ -272,21 +334,21 @@ export default {
<el-button <el-button
type="text" type="text"
class="btn flex btnBox" class="btn flex btnBox"
@click="downloadFile(scope.row)" @click="downloadFile(scope.row.batchArrangeNum)"
> >
<img src="../../assets/download.png" width="30" height="30" /> <img src="../../assets/download.png" width="30" height="30" />
<div>下载素材</div></el-button <div>下载素材</div></el-button
> >
<el-button <el-button
type="text" type="text"
disabled :disabled="scope.row.layoutStatus == 2"
class="btn flex btnBox" class="btn flex btnBox"
@click="changeTypesetting(scope.row)" @click="changeTypesetting(scope.row.batchArrangeNum)"
><img ><img
src="../../assets/typesetting.png" src="../../assets/typesetting.png"
width="30" width="30"
height="30" height="30"
:class="{ disabled: false }" :class="{ disabled: scope.row.layoutStatus == 2 }"
/> />
<div>排版</div> <div>排版</div>
</el-button> </el-button>
......
...@@ -21,26 +21,24 @@ ...@@ -21,26 +21,24 @@
<div class="setting-group"> <div class="setting-group">
<div class="group-title">素材超排版宽度时:</div> <div class="group-title">素材超排版宽度时:</div>
<el-radio-group v-model="form.overWidthMode"> <el-radio-group v-model="form.widthStrategy">
<el-radio label="autoScale">自动缩小素材,适配烫画模宽度</el-radio> <el-radio :label="1">自动缩小素材,适配烫画模宽度</el-radio>
<el-radio label="skip">超出排版宽度不排版</el-radio> <el-radio :label="2">超出排版宽度不排版</el-radio>
<el-radio label="biggerSize" <el-radio :label="3">超出排版宽度,使用更大规格排版</el-radio>
>超出排版宽度,使用更大规格排版</el-radio
>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="setting-group"> <div class="setting-group">
<div class="group-title">单张排版最大素材数:</div> <div class="group-title">单张排版最大素材数:</div>
<el-radio-group v-model="form.maxPicMode"> <el-radio-group v-model="form.materialStrategy">
<el-radio label="batch">批次素材数</el-radio> <el-radio :label="1">批次素材数</el-radio>
<div class="custom-num-row"> <div class="custom-num-row">
<el-radio label="custom">自定义素材数(建议数量30):</el-radio> <el-radio :label="2">自定义素材数(建议数量30):</el-radio>
<el-input <el-input
v-model.number="form.customPicNum" v-model.number="form.materialCount"
placeholder="请输入素材数" placeholder="请输入素材数"
style="width: 180px; margin-left: 8px" style="width: 180px; margin-left: 8px"
:disabled="form.maxPicMode !== 'custom'" :disabled="form.materialStrategy !== '2'"
/> />
</div> </div>
</el-radio-group> </el-radio-group>
...@@ -48,10 +46,10 @@ ...@@ -48,10 +46,10 @@
<div class="setting-group"> <div class="setting-group">
<div class="group-title">自动排版设置</div> <div class="group-title">自动排版设置</div>
<el-radio-group v-model="form.autoLayoutType"> <el-radio-group v-model="form.autoLayoutStrategy">
<el-radio label="40+2">40+2</el-radio> <el-radio :label="1">40+2</el-radio>
<el-radio label="60">60</el-radio> <el-radio :label="2">60</el-radio>
<el-radio label="none">不执行自动排版</el-radio> <el-radio :label="3">不执行自动排版</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
...@@ -78,25 +76,19 @@ ...@@ -78,25 +76,19 @@
<script> <script>
const { ipcRenderer } = require("electron"); const { ipcRenderer } = require("electron");
const { const { setDTFSetting, getDTFSetting } = require("@/server/utils/store");
getProductType,
setProductType,
setDTFSetting,
getDTFSetting
} = require("@/server/utils/store");
export default { export default {
name: "dtf-setting", name: "dtf-setting",
data() { data() {
return { return {
// 表单配置,可从本地配置文件读取初始化 // 表单配置,可从本地配置文件读取初始化
form: { ...getDTFSetting() }, form: { ...getDTFSetting() }
activeName: getProductType()
}; };
}, },
mounted() { mounted() {
// 页面加载读取本地配置回填表单 // 页面加载读取本地配置回填表单
this.loadLocalConfig(); // this.loadLocalConfig();
}, },
methods: { methods: {
// 返回上一页 // 返回上一页
...@@ -105,12 +97,13 @@ export default { ...@@ -105,12 +97,13 @@ export default {
}, },
// 读取本地配置 // 读取本地配置
async loadLocalConfig() { async loadLocalConfig() {
ipcRenderer.send("read-layout-config"); try {
ipcRenderer.once("layout-config-data", (_, cfg) => { const { data } = await this.$api.post("/productionConfig");
if (cfg) { this.form = { ...data };
this.form = Object.assign({}, this.form, cfg); setDTFSetting({ ...this.form });
} } catch (error) {
}); console.log(error);
}
}, },
// 选择文件夹弹窗 // 选择文件夹弹窗
selectFolder() { selectFolder() {
...@@ -120,11 +113,8 @@ export default { ...@@ -120,11 +113,8 @@ export default {
}); });
}, },
// 保存配置到本地文件 // 保存配置到本地文件
saveConfig() { async saveConfig() {
if ( if (this.form.autoLayoutStrategy == 2 && this.form.widthStrategy == 3) {
this.form.autoLayoutType == "60" &&
this.form.overWidthMode === "biggerSize"
) {
this.$confirm( this.$confirm(
"由于排版设置中选择“按更大规格排版”仅适用于40+2,选60时,默认超60的规格不排版", "由于排版设置中选择“按更大规格排版”仅适用于40+2,选60时,默认超60的规格不排版",
"提示", "提示",
...@@ -132,17 +122,11 @@ export default { ...@@ -132,17 +122,11 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
type: "warning" type: "warning"
} }
).then(() => { );
this.$message.success("排版设置保存成功!");
});
} else {
this.$message.success("排版设置保存成功!");
} }
await this.$api.post("/productionConfigUpdate", this.form);
setDTFSetting({ ...this.form }); setDTFSetting({ ...this.form });
}, this.$message.success("排版设置保存成功!");
tabClick(tab) {
if (tab.name == "DTG") this.goBack();
setProductType(tab.name);
} }
} }
}; };
......
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