From 56d52656426f71e8d53bea63b3d07a564d3ecd85 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 27 三月 2026 14:44:14 +0800
Subject: [PATCH] 生产流程卡(成品)
---
src/api/salesManagement/salesLedger.js | 8
src/views/salesManagement/salesLedger/components/processCardPrint.js | 261 ++++++++++++++++
src/views/salesManagement/salesLedger/index.vue | 670 +---------------------------------------
3 files changed, 300 insertions(+), 639 deletions(-)
diff --git a/src/api/salesManagement/salesLedger.js b/src/api/salesManagement/salesLedger.js
index 7ded652..fe778af 100644
--- a/src/api/salesManagement/salesLedger.js
+++ b/src/api/salesManagement/salesLedger.js
@@ -168,4 +168,12 @@
url: `/sales/ledger/salesProcess/${salesLedgerId}`,
method: "get",
});
+}
+
+// 鎵撳嵃鐢熶骇娴佺▼鍗★紙鎴愬搧锛�
+export function getProcessCard(salesLedgerId) {
+ return request({
+ url: `/sales/ledger/processCard/${salesLedgerId}`,
+ method: "get",
+ });
}
\ No newline at end of file
diff --git a/src/views/salesManagement/salesLedger/components/processCardPrint.js b/src/views/salesManagement/salesLedger/components/processCardPrint.js
new file mode 100644
index 0000000..d89ee18
--- /dev/null
+++ b/src/views/salesManagement/salesLedger/components/processCardPrint.js
@@ -0,0 +1,261 @@
+const PRINT_TITLE = "鐢熶骇娴佺▼鍗�(鎴愬搧)";
+
+const formatDisplayDate = (value) => {
+ if (!value) return "";
+ const date = new Date(value);
+ if (Number.isNaN(date.getTime())) return String(value);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const day = String(date.getDate()).padStart(2, "0");
+ return `${year}/${month}/${day}`;
+};
+
+const getCurrentDate = () => {
+ const date = new Date();
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const day = String(date.getDate()).padStart(2, "0");
+ return `${year}/${month}/${day}`;
+};
+
+const escapeHtml = (value) =>
+ String(value ?? "")
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """)
+ .replaceAll("'", "'");
+
+const renderRouteHeader = (routeNodes) => {
+ const columns = (Array.isArray(routeNodes) ? routeNodes : [])
+ .sort((a, b) => (a?.dragSort ?? 0) - (b?.dragSort ?? 0))
+ .map((node) => `<th class="route-col">${escapeHtml(node?.processRouteItemName)}</th>`)
+ .join("");
+ return columns || '<th class="route-col">宸ュ簭</th>';
+};
+
+const renderRouteRow = (routeNodes) => {
+ const columns = (Array.isArray(routeNodes) ? routeNodes : [])
+ .sort((a, b) => (a?.dragSort ?? 0) - (b?.dragSort ?? 0))
+ .map(() => '<td class="route-col">娆″搧</td>')
+ .join("");
+ return columns || '<td class="route-col">娆″搧</td>';
+};
+
+const renderRouteEmptyCells = (routeNodes) => {
+ const columns = (Array.isArray(routeNodes) ? routeNodes : [])
+ .sort((a, b) => (a?.dragSort ?? 0) - (b?.dragSort ?? 0))
+ .map(() => '<td class="route-col"></td>')
+ .join("");
+ return columns || '<td class="route-col"></td>';
+};
+
+const renderItems = (items, startIndex, routeNodes, totalCols) => {
+ const list = Array.isArray(items) ? items : [];
+ if (list.length === 0) {
+ return `<tr><td colspan="${totalCols}" style="text-align:center;">鏆傛棤鏄庣粏</td></tr>`;
+ }
+ const routeEmptyCells = renderRouteEmptyCells(routeNodes);
+ return list
+ .map(
+ (item, index) => `
+ <tr>
+ <td>${startIndex + index + 1}</td>
+ <td class="no-wrap">${escapeHtml(item?.floorCode)}</td>
+ <td class="no-wrap">${escapeHtml(item?.width)} * ${escapeHtml(item?.height)}</td>
+ <td class="no-wrap">${escapeHtml(item?.quantity)}</td>
+ <td class="no-wrap">${escapeHtml(item?.area)}</td>
+ <td class="no-wrap">${escapeHtml(item?.processRequirement)}</td>
+ ${routeEmptyCells}
+ </tr>
+ `
+ )
+ .join("");
+};
+
+const splitItemsByPage = (items, pageSize) => {
+ const list = Array.isArray(items) ? items : [];
+ if (list.length === 0) return [[]];
+ const pages = [];
+ for (let i = 0; i < list.length; i += pageSize) {
+ pages.push(list.slice(i, i + pageSize));
+ }
+ return pages;
+};
+
+export const printFinishedProcessCard = (cardData) => {
+ const data = cardData ?? {};
+ const routeNodes = Array.isArray(data.routeNodes) ? data.routeNodes : [];
+ const items = Array.isArray(data.items) ? data.items : [];
+ const firstItem = items[0] ?? {};
+ const productName = firstItem.productDescription || "";
+ const totalCols = 6 + Math.max(routeNodes.length, 1);
+ const signLabelCols = 2;
+ const signBlankCols = Math.max(totalCols - 5 - signLabelCols, 1);
+ const pageSize = 10;
+ const itemPages = splitItemsByPage(items, pageSize);
+ const totalPages = itemPages.length;
+
+ const printWindow = window.open("", "_blank", "width=1200,height=900");
+ if (!printWindow) {
+ throw new Error("娴忚鍣ㄦ嫤鎴簡寮圭獥锛岃鍏佽寮圭獥鍚庨噸璇�");
+ }
+
+ const html = `
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>${PRINT_TITLE}</title>
+ <style>
+ body { margin: 0; padding: 0; font-family: "SimSun", serif; color: #222; }
+ .page { width: 198mm; margin: 0 auto; padding: 6mm 3mm 5mm; box-sizing: border-box; page-break-after: always; }
+ .page:last-child { page-break-after: auto; }
+ .table-wrap { position: relative; }
+ .page-mark {
+ position: absolute;
+ left: 0;
+ top: -16px;
+ z-index: 2;
+ font-size: 12px;
+ line-height: 1;
+ background: #fff;
+ padding: 0 2px;
+ }
+ .title { text-align: center; font-size: 18px; font-weight: 700; margin-bottom: 4px; line-height: 1.2; }
+ .sub-title { font-size: 14px; }
+ table { width: 100%; border-collapse: collapse; table-layout: auto; }
+ td, th { border: 0.8px solid #6f7f95; padding: 2px 4px; font-size: 12px; text-align: center; vertical-align: middle; word-break: break-all; }
+ .left { text-align: left; }
+ .no-wrap { white-space: nowrap; word-break: keep-all; }
+ .route-col { min-width: 48px; white-space: nowrap; word-break: keep-all; }
+ .section-title { font-weight: 700; text-align: left; padding-left: 6px; }
+ .sign-label { text-align: left; padding-left: 8px; vertical-align: top; line-height: 1.2; }
+ .sign-blank { vertical-align: top; min-height: 18px; }
+ .order-req-content { min-height: 82px; vertical-align: top; padding-top: 6px; }
+ .sign-row td { height: 18px; }
+ .order-require-title { width: 34px; padding: 0; }
+ .order-require-title-text {
+ display: flex;
+ height: 100%;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ line-height: 1.25;
+ letter-spacing: 0;
+ font-weight: 500;
+ }
+ .footer { margin-top: 10px; font-size: 12px; line-height: 1.7; padding: 0 2px; }
+ .footer-row { display: flex; justify-content: space-between; }
+ .footer-item { width: 33%; }
+ .continued { text-align: right; font-size: 12px; padding-right: 8px; }
+ @media print {
+ @page { size: A4 portrait; margin: 8mm; }
+ .page { width: 100%; margin: 0; padding: 0; }
+ }
+ </style>
+ </head>
+ <body>
+ ${itemPages
+ .map((pageItems, pageIndex) => {
+ const isLastPage = pageIndex === totalPages - 1;
+ const startIndex = pageIndex * pageSize;
+ return `
+ <div class="page">
+ <div class="title">楣ゅ澶╂矏閽㈠寲鐜荤拑鍘�<br /><span class="sub-title">鐢熶骇娴佺▼鍗�(鎴愬搧)</span></div>
+ <div class="table-wrap">
+ <div class="page-mark">绗�${pageIndex + 1}椤碉紝鍏�${totalPages}椤�</div>
+ <table>
+ <thead>
+ <tr>
+ <td colspan="5" class="left">璁㈠崟缂栧彿:${escapeHtml(data.salesContractNo)}</td>
+ <td colspan="${totalCols - 5}" class="left">浜よ揣鏃ユ湡:${escapeHtml(formatDisplayDate(data.deliveryDate))}</td>
+ </tr>
+ <tr>
+ <td colspan="5" class="left">瀹㈡埛鍚嶇О:${escapeHtml(data.customerName)}</td>
+ <td colspan="${totalCols - 5}" class="left">宸ヨ壓娴佺▼:${escapeHtml(data.processPathDisplay)}</td>
+ </tr>
+ <tr>
+ <th rowspan="2" style="width:6%;">璁㈠簭</th>
+ <th rowspan="2" style="width:22%;" class="no-wrap">妤煎眰缂栧彿</th>
+ <th rowspan="2" style="width:20%;" class="no-wrap">瀹�(寮ч暱)*楂�</th>
+ <th rowspan="2" style="width:8%;" class="no-wrap">鏁伴噺</th>
+ <th rowspan="2" style="width:8%;" class="no-wrap">闈㈢Н</th>
+ <th rowspan="2" style="width:20%;" class="no-wrap">鏄庣粏鍔犲伐瑕佹眰</th>
+ ${renderRouteHeader(routeNodes)}
+ </tr>
+ <tr>${renderRouteRow(routeNodes)}</tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td colspan="${totalCols}" class="section-title">浜у搧鍚嶇О:${escapeHtml(productName)}</td>
+ </tr>
+ ${renderItems(pageItems, startIndex, routeNodes, totalCols)}
+ ${
+ isLastPage
+ ? `<tr>
+ <td colspan="3" class="left"><strong>鍚堣:</strong></td>
+ <td>${escapeHtml(data.totalQuantity)}</td>
+ <td>${escapeHtml(data.totalArea)}</td>
+ <td colspan="${signLabelCols}" class="sign-label">瀹屽伐绛惧悕</td>
+ <td colspan="${signBlankCols}" class="sign-blank"></td>
+ </tr>
+ <tr class="sign-row">
+ <td rowspan="3" class="order-require-title">
+ <div class="order-require-title-text">
+ <span>璁㈠崟</span>
+ <span>鍔犲伐</span>
+ <span>瑕佹眰</span>
+ </div>
+ </td>
+ <td colspan="4" rowspan="3" class="left order-req-content">${escapeHtml(data.orderProcessRequirement)}</td>
+ <td colspan="${signLabelCols}" class="sign-label">璐ㄦ绛惧悕</td>
+ <td colspan="${signBlankCols}" class="sign-blank"></td>
+ </tr>
+ <tr class="sign-row">
+ <td colspan="${signLabelCols}" class="sign-label">鎺ユ敹绛惧悕</td>
+ <td colspan="${signBlankCols}" class="sign-blank"></td>
+ </tr>
+ <tr class="sign-row">
+ <td colspan="${signLabelCols}" class="sign-label">鐢熶骇鏃ユ湡</td>
+ <td colspan="${signBlankCols}" class="sign-blank"></td>
+ </tr>`
+ : `<tr><td colspan="${totalCols}" class="continued">涓嬮〉缁�...</td></tr>`
+ }
+ </tbody>
+ </table>
+ </div>
+
+ ${
+ isLastPage
+ ? `<div class="footer">
+ <div class="footer-row">
+ <div class="footer-item">鍒跺崟鍛�:${escapeHtml(data.register)}</div>
+ <div class="footer-item">瀹℃牳鍛�:__________</div>
+ <div class="footer-item">宸ヨ壓鍛�:${escapeHtml(data.technician ?? "")}</div>
+ </div>
+ <div class="footer-row">
+ <div class="footer-item">鍒跺崟鏃ユ湡:${escapeHtml(formatDisplayDate(data.registerDate))}</div>
+ <div class="footer-item">瀹℃牳鏃ユ湡:__________</div>
+ <div class="footer-item">鎵撳嵃鏃ユ湡:${getCurrentDate()}</div>
+ </div>
+ </div>`
+ : ""
+ }
+ </div>`;
+ })
+ .join("")}
+ </body>
+</html>
+`;
+
+ printWindow.document.write(html);
+ printWindow.document.close();
+ printWindow.onload = () => {
+ setTimeout(() => {
+ printWindow.focus();
+ printWindow.print();
+ printWindow.close();
+ }, 300);
+ };
+};
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index dd209c7..8f69d26 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -45,7 +45,16 @@
<el-button type="primary" plain @click="handleImport">瀵煎叆</el-button>
<el-button @click="handleOut">瀵煎嚭</el-button>
<el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
- <el-button type="primary" plain @click="handlePrint">鎵撳嵃</el-button>
+ <el-dropdown @command="handlePrintCommand">
+ <el-button type="primary" plain>
+ 鎵撳嵃鍗曟嵁<el-icon class="el-icon--right"><ArrowDown /></el-icon>
+ </el-button>
+ <template #dropdown>
+ <el-dropdown-menu>
+ <el-dropdown-item command="finishedProcessCard">鎵撳嵃鐢熶骇娴佺▼鍗★紙鎴愬搧锛�</el-dropdown-item>
+ </el-dropdown-menu>
+ </template>
+ </el-dropdown>
</div>
</div>
<el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
@@ -773,122 +782,6 @@
v-model="fileListDialogVisible"
title="闄勪欢鍒楄〃"
/>
- <!-- 鎵撳嵃棰勮寮圭獥 -->
- <el-dialog
- v-model="printPreviewVisible"
- title="鎵撳嵃棰勮"
- width="90%"
- :close-on-click-modal="false"
- class="print-preview-dialog"
- >
- <div class="print-preview-container">
- <div class="print-preview-header">
- <el-button type="primary" @click="executePrint">鎵ц鎵撳嵃</el-button>
- <el-button @click="printPreviewVisible = false">鍏抽棴棰勮</el-button>
- </div>
- <div class="print-preview-content">
- <div v-if="printData.length === 0" style="text-align: center; padding: 50px; color: #999;">
- 鏆傛棤鎵撳嵃鏁版嵁
- </div>
- <div v-else style="text-align: center; padding: 10px; color: #666; font-size: 14px; background: #e8f4fd; margin-bottom: 10px;">
- 鍏� {{ printData.length }} 鏉℃暟鎹緟鎵撳嵃
- </div>
- <div v-for="(item, index) in printData" :key="index" class="print-page">
- <div class="delivery-note">
- <div class="header">
- <div class="document-title">闆跺敭鍙戣揣鍗�</div>
- </div>
-
- <div class="info-section">
- <div class="info-row">
- <div>
- <span class="label">鍙戣揣鏃ユ湡锛�</span>
- <span class="value">{{ formatDate(item.createTime) }}</span>
- </div>
- <div>
- <span class="label">鍙戣揣杞︾墝鍙凤細</span>
- <span class="value">{{ item.shippingCarNumber }}</span>
- </div>
- </div>
- <div class="info-row">
- <div>
- <span class="label">瀹㈡埛鍚嶇О锛�</span>
- <span class="value">{{ item.customerName }}</span>
- </div>
- <span class="label">鍗曞彿锛�</span>
- <span class="value">{{ item.salesContractNo }}</span>
- </div>
- </div>
-
- <div class="table-section">
- <table class="product-table">
- <thead>
- <tr>
- <th>浜у搧鍚嶇О</th>
- <th>瑙勬牸鍨嬪彿</th>
- <th>鍘氬害</th>
- <th>鍗曚环</th>
- <th>闆跺敭鏁伴噺</th>
- <th>闆跺敭閲戦</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="product in item.products" :key="product.id">
- <td>{{ product.productCategory || '' }}</td>
- <td>{{ product.specificationModel || '' }}</td>
- <td>{{ product.thickness ?? '' }}</td>
- <td>{{ product.taxInclusiveUnitPrice || '0' }}</td>
- <td>{{ product.quantity || '0' }}</td>
- <td>{{ product.taxInclusiveTotalPrice || '0' }}</td>
- </tr>
- <tr v-if="!item.products || item.products.length === 0">
- <td colspan="6" style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁</td>
- </tr>
- </tbody>
- <tfoot>
- <tr>
- <td class="label">鍚堣</td>
- <td class="total-value"></td>
- <td class="total-value"></td>
- <td class="total-value"></td>
- <td class="total-value">{{ getTotalQuantity(item.products) }}</td>
- <td class="total-value">{{ getTotalAmount(item.products) }}</td>
- </tr>
- </tfoot>
- </table>
- </div>
-
- <div class="footer-section">
- <div class="footer-row">
- <div class="footer-item">
- <span class="label">鏀惰揣鐢佃瘽锛�</span>
- <span class="value"></span>
- </div>
- <div class="footer-item">
- <span class="label">鏀惰揣浜猴細</span>
- <span class="value"></span>
- </div>
- <div class="footer-item address-item">
- <span class="label">鏀惰揣鍦板潃锛�</span>
- <span class="value address-value"></span>
- </div>
- </div>
- <div class="footer-row">
- <div class="footer-item">
- <span class="label">鎿嶄綔鍛橈細</span>
- <span class="value">{{ userStore.nickName || '鎾曞紑鍓�' }}</span>
- </div>
- <div class="footer-item">
- <span class="label">鎵撳嵃鏃ユ湡锛�</span>
- <span class="value">{{ formatDateTime(new Date()) }}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </el-dialog>
<!-- 鍙戣揣寮规 -->
<el-dialog
v-model="deliveryFormVisible"
@@ -973,7 +866,7 @@
import {onMounted, ref, getCurrentInstance} from "vue";
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
import { ElMessageBox, ElMessage } from "element-plus";
-import { UploadFilled, Download } from "@element-plus/icons-vue";
+import { ArrowDown } from "@element-plus/icons-vue";
import useUserStore from "@/store/modules/user";
import { userListNoPage } from "@/api/system/user.js";
import FileListDialog from '@/components/Dialog/FileListDialog.vue';
@@ -996,11 +889,13 @@
salesLedgerProductProcessList,
saleProcessBind,
getSaleProcessBindInfo,
+ getProcessCard,
} from "@/api/salesManagement/salesLedger.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import { getCurrentDate } from "@/utils/index.js";
+import { printFinishedProcessCard } from "./components/processCardPrint.js";
// import { salesLedgerProductSetProcessFlowConfig } from "@/api/salesManagement/salesProcessFlowConfig.js";
const userStore = useUserStore();
@@ -1121,10 +1016,6 @@
// 璁剧疆涓婁紶鐨勮姹傚ご閮�
headers: { Authorization: "Bearer " + getToken() },
});
-// 鎵撳嵃鐩稿叧
-const printPreviewVisible = ref(false);
-const printData = ref([]);
-
// 鎶ヤ环鍗曞鍏ョ浉鍏�
const quotationDialogVisible = ref(false);
const quotationLoading = ref(false);
@@ -2131,364 +2022,31 @@
});
};
-// 鎵撳嵃鍔熻兘
-const handlePrint = async () => {
- if (selectedRows.value.length === 0) {
- proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
+const handlePrintCommand = async (command) => {
+ if (command !== "finishedProcessCard") return;
+ if (selectedRows.value.length !== 1) {
+ proxy.$modal.msgWarning("璇烽�夋嫨涓�鏉¢攢鍞彴璐︽暟鎹繘琛屾墦鍗�");
return;
}
-
- // 鏄剧ず鍔犺浇鐘舵��
- proxy.$modal.loading("姝e湪鑾峰彇浜у搧鏁版嵁锛岃绋嶅��...");
-
+
+ const selectedRow = selectedRows.value[0];
+ const selectedId = selectedRow?.id;
+ if (!selectedId) {
+ proxy.$modal.msgWarning("褰撳墠閫夋嫨鏁版嵁缂哄皯ID锛屾棤娉曟墦鍗�");
+ return;
+ }
+
+ proxy.$modal.loading("姝e湪鑾峰彇鐢熶骇娴佺▼鍗℃暟鎹紝璇风◢鍊�...");
try {
- // 涓烘瘡涓�変腑鐨勯攢鍞彴璐﹁褰曟煡璇㈠搴旂殑浜у搧鏁版嵁
- const printDataWithProducts = [];
-
- for (const row of selectedRows.value) {
- try {
- // 璋冪敤productList鎺ュ彛鏌ヨ浜у搧鏁版嵁
- const productRes = await productList({ salesLedgerId: row.id, type: 1 });
-
- // 灏嗕骇鍝佹暟鎹暣鍚堝埌閿�鍞彴璐﹁褰曚腑
- const rowWithProducts = {
- ...row,
- products: productRes.data || []
- };
-
- printDataWithProducts.push(rowWithProducts);
- } catch (error) {
- console.error(`鑾峰彇閿�鍞彴璐� ${row.id} 鐨勪骇鍝佹暟鎹け璐�:`, error);
- // 鍗充娇鏌愪釜璁板綍鐨勪骇鍝佹暟鎹幏鍙栧け璐ワ紝涔熻鍖呭惈璇ヨ褰�
- printDataWithProducts.push({
- ...row,
- products: []
- });
- }
- }
-
- printData.value = printDataWithProducts;
- console.log('鎵撳嵃鏁版嵁锛堝寘鍚骇鍝侊級:', printData.value);
- printPreviewVisible.value = true;
-
+ const res = await getProcessCard(selectedId);
+ const processCardData = res?.data ?? {};
+ printFinishedProcessCard(processCardData);
} catch (error) {
- console.error('鑾峰彇浜у搧鏁版嵁澶辫触:', error);
- proxy.$modal.msgError("鑾峰彇浜у搧鏁版嵁澶辫触锛岃閲嶈瘯");
+ console.error("鎵撳嵃鐢熶骇娴佺▼鍗″け璐�:", error);
+ proxy.$modal.msgError("鎵撳嵃澶辫触锛岃绋嶅悗閲嶈瘯");
} finally {
proxy.$modal.closeLoading();
}
-};
-// 鎵ц鎵撳嵃
-const executePrint = () => {
- console.log('寮�濮嬫墽琛屾墦鍗帮紝鏁版嵁鏉℃暟:', printData.value.length);
- console.log('鎵撳嵃鏁版嵁:', printData.value);
-
- // 鍒涘缓涓�涓柊鐨勬墦鍗扮獥鍙�
- const printWindow = window.open('', '_blank', 'width=800,height=600');
-
- // 鏋勫缓鎵撳嵃鍐呭
- let printContent = `
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>鎵撳嵃棰勮</title>
- <style>
- body {
- margin: 0;
- padding: 0;
- font-family: "SimSun", serif;
- background: white;
- }
- .print-page {
- width: 200mm;
- height: 75mm;
- padding: 10mm;
- padding-left: 20mm;
- background: white;
- box-sizing: border-box;
- page-break-after: always;
- page-break-inside: avoid;
- }
- .print-page:last-child {
- page-break-after: avoid;
- }
- .delivery-note {
- width: 100%;
- height: 100%;
- font-size: 12px;
- line-height: 1.2;
- display: flex;
- flex-direction: column;
- color: #000;
- }
- .header {
- text-align: center;
- margin-bottom: 8px;
- }
- .company-name {
- font-size: 18px;
- font-weight: bold;
- margin-bottom: 4px;
- }
- .document-title {
- font-size: 16px;
- font-weight: bold;
- }
- .info-section {
- margin-bottom: 8px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .info-row {
- line-height: 20px;
- }
- .label {
- font-weight: bold;
- width: 60px;
- font-size: 12px;
- }
- .value {
- margin-right: 20px;
- min-width: 80px;
- font-size: 12px;
- }
- .table-section {
- margin-bottom: 40px;
- // flex: 0.6;
- }
- .product-table {
- width: 100%;
- border-collapse: collapse;
- border: 1px solid #000;
- }
- .product-table th, .product-table td {
- border: 1px solid #000;
- padding: 6px;
- text-align: center;
- font-size: 12px;
- line-height: 1.4;
- }
- .product-table th {
- font-weight: bold;
- }
- .total-value {
- font-weight: bold;
- }
- .footer-section {
- margin-top: auto;
- }
- .footer-row {
- display: flex;
- margin-bottom: 3px;
- line-height: 22px;
- justify-content: space-between;
- }
- .footer-item {
- display: flex;
- margin-right: 20px;
- }
- .footer-item .label {
- font-weight: bold;
- width: 80px;
- font-size: 12px;
- }
- .footer-item .value {
- min-width: 80px;
- font-size: 12px;
- }
- .address-item .address-value {
- min-width: 200px;
- }
- @media print {
- body {
- margin: 0;
- padding: 0;
- }
- .print-page {
- margin: 0;
- padding: 10mm;
- /* padding-left: 20mm; */
- page-break-inside: avoid;
- page-break-after: always;
- }
- .print-page:last-child {
- page-break-after: avoid;
- }
- }
- </style>
- </head>
- <body>
- `;
-
- // 涓烘瘡鏉℃暟鎹敓鎴愭墦鍗伴〉闈�
- printData.value.forEach((item, index) => {
- printContent += `
- <div class="print-page">
- <div class="delivery-note">
- <div class="header">
- <div class="document-title">闆跺敭鍙戣揣鍗�</div>
- </div>
-
- <div class="info-section">
- <div class="info-row">
- <div>
- <span class="label">鍙戣揣鏃ユ湡锛�</span>
- <span class="value">${formatDate(item.createTime)}</span>
- </div>
- <div>
- <span class="label">瀹㈡埛鍚嶇О锛�</span>
- <span class="value">${item.customerName}</span>
- </div>
- </div>
- <div class="info-row">
- <span class="label">鍗曞彿锛�</span>
- <span class="value">${item.salesContractNo || ''}</span>
- </div>
- </div>
-
- <div class="table-section">
- <table class="product-table">
- <thead>
- <tr>
- <th>浜у搧鍚嶇О</th>
- <th>瑙勬牸鍨嬪彿</th>
- <th>鍘氬害</th>
- <th>鍗曚环</th>
- <th>闆跺敭鏁伴噺</th>
- <th>闆跺敭閲戦</th>
- </tr>
- </thead>
- <tbody>
- ${item.products && item.products.length > 0 ?
- item.products.map(product => `
- <tr>
- <td>${product.productCategory || ''}</td>
- <td>${product.specificationModel || ''}</td>
- <td>${product.thickness ?? ''}</td>
- <td>${product.taxInclusiveUnitPrice || '0'}</td>
- <td>${product.quantity || '0'}</td>
- <td>${product.taxInclusiveTotalPrice || '0'}</td>
- </tr>
- `).join('') :
- '<tr><td colspan="6" style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁</td></tr>'
- }
- </tbody>
- <tfoot>
- <tr>
- <td class="label">鍚堣</td>
- <td class="total-value"></td>
- <td class="total-value"></td>
- <td class="total-value"></td>
- <td class="total-value">${getTotalQuantityForPrint(item.products)}</td>
- <td class="total-value">${getTotalAmountForPrint(item.products)}</td>
- </tr>
- </tfoot>
- </table>
- </div>
-
- <div class="footer-section">
- <div class="footer-row">
- <div class="footer-item">
- <span class="label">鏀惰揣鐢佃瘽锛�</span>
- <span class="value"></span>
- </div>
- <div class="footer-item">
- <span class="label">鏀惰揣浜猴細</span>
- <span class="value"></span>
- </div>
- <div class="footer-item address-item">
- <span class="label">鏀惰揣鍦板潃锛�</span>
- <span class="value address-value"></span>
- </div>
- </div>
- <div class="footer-row">
- <div class="footer-item">
- <span class="label">鎿嶄綔鍛橈細</span>
- <span class="value">${userStore.nickName || '鎾曞紑鍓�'}</span>
- </div>
- <div class="footer-item">
- <span class="label">鎵撳嵃鏃ユ湡锛�</span>
- <span class="value">${formatDateTime(new Date())}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
- `;
- });
-
- printContent += `
- </body>
- </html>
- `;
-
- // 鍐欏叆鍐呭鍒版柊绐楀彛
- printWindow.document.write(printContent);
- printWindow.document.close();
-
- // 绛夊緟鍐呭鍔犺浇瀹屾垚鍚庢墦鍗�
- printWindow.onload = () => {
- setTimeout(() => {
- printWindow.print();
- printWindow.close();
- printPreviewVisible.value = false;
- }, 500);
- };
-};
-// 鏍煎紡鍖栨棩鏈�
-const formatDate = (dateString) => {
- if (!dateString) return getCurrentDate();
- const date = new Date(dateString);
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, "0");
- const day = String(date.getDate()).padStart(2, "0");
- return `${year}/${month}/${day}`;
-};
-// 鏍煎紡鍖栨棩鏈熸椂闂�
-const formatDateTime = (date) => {
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, "0");
- const day = String(date.getDate()).padStart(2, "0");
- const hours = String(date.getHours()).padStart(2, "0");
- const minutes = String(date.getMinutes()).padStart(2, "0");
- const seconds = String(date.getSeconds()).padStart(2, "0");
- return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
-};
-// 璁$畻浜у搧鎬绘暟閲�
-const getTotalQuantity = (products) => {
- if (!products || products.length === 0) return '0';
- const total = products.reduce((sum, product) => {
- return sum + (parseFloat(product.quantity) || 0);
- }, 0);
- return total.toFixed(2);
-};
-
-// 璁$畻浜у搧鎬婚噾棰�
-const getTotalAmount = (products) => {
- if (!products || products.length === 0) return '0';
- const total = products.reduce((sum, product) => {
- return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
- }, 0);
- return total.toFixed(2);
-};
-
-// 鐢ㄤ簬鎵撳嵃鐨勮绠楀嚱鏁�
-const getTotalQuantityForPrint = (products) => {
- if (!products || products.length === 0) return '0';
- const total = products.reduce((sum, product) => {
- return sum + (parseFloat(product.quantity) || 0);
- }, 0);
- return total.toFixed(2);
-};
-
-const getTotalAmountForPrint = (products) => {
- if (!products || products.length === 0) return '0';
- const total = products.reduce((sum, product) => {
- return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
- }, 0);
- return total.toFixed(2);
};
const mathNum = () => {
@@ -3031,171 +2589,5 @@
display: flex;
justify-content: space-between;
margin-bottom: 10px;
-}
-.print-preview-dialog {
- .el-dialog__body {
- padding: 0;
- max-height: 80vh;
- overflow-y: auto;
- }
-}
-
-.print-preview-container {
- .print-preview-header {
- padding: 15px;
- border-bottom: 1px solid #e4e7ed;
- text-align: center;
-
- .el-button {
- margin: 0 10px;
- }
- }
-
- .print-preview-content {
- padding: 20px;
- background-color: #f5f5f5;
- min-height: 400px;
- }
-}
-
-.print-page {
- width: 220mm;
- height: 90mm;
- padding: 10mm;
- margin: 0 auto;
- background: white;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
- margin-bottom: 10px;
- box-sizing: border-box;
-}
-
-.delivery-note {
- width: 100%;
- height: 100%;
- font-family: "SimSun", serif;
- font-size: 10px;
- line-height: 1.2;
- display: flex;
- flex-direction: column;
-}
-
-.header {
- text-align: center;
- margin-bottom: 8px;
-
- .company-name {
- font-size: 18px;
- font-weight: bold;
- margin-bottom: 4px;
- }
-
- .document-title {
- font-size: 16px;
- font-weight: bold;
- }
-}
-
-.info-section {
- margin-bottom: 8px;
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- .info-row {
- line-height: 20px;
-
- .label {
- font-weight: bold;
- width: 60px;
- font-size: 14px;
- }
-
- .value {
- margin-right: 20px;
- min-width: 80px;
- font-size: 14px;
- }
- }
-}
-
-.table-section {
- margin-bottom: 4px;
- flex: 1;
-
- .product-table {
- width: 100%;
- border-collapse: collapse;
- border: 1px solid #000;
-
- th, td {
- border: 1px solid #000;
- padding: 6px;
- text-align: center;
- font-size: 14px;
- line-height: 1.4;
- }
-
- th {
- font-weight: bold;
- }
-
- .total-label {
- text-align: right;
- font-weight: bold;
- }
-
- .total-value {
- font-weight: bold;
- }
- }
-}
-
-.footer-section {
- .footer-row {
- display: flex;
- margin-bottom: 3px;
- line-height: 20px;
- justify-content: space-between;
-
- .footer-item {
- display: flex;
- margin-right: 20px;
-
- .label {
- font-weight: bold;
- width: 80px;
- font-size: 14px;
- }
-
- .value {
- min-width: 80px;
- font-size: 14px;
- }
-
- &.address-item {
- .address-value {
- min-width: 200px;
- }
- }
- }
- }
-}
-
-@media print {
- .app-container {
- display: none;
- }
-
- .print-page {
- box-shadow: none;
- margin: 0;
- padding: 10mm;
- padding-left: 20mm;
- page-break-inside: avoid;
- page-break-after: always;
- }
- .print-page:last-child {
- page-break-after: avoid;
- }
}
</style>
--
Gitblit v1.9.3