Files
17168ERP/web/admin/print/print_multi_new.aspx
2026-03-26 18:08:20 +08:00

516 lines
21 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="print_multi_new.aspx.cs" Inherits="admin_print_print_multi_new" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<link href="~/js/bootstrap5/bootstrap.min.css" rel="stylesheet" />
<%--<link href="~/js/fontawesome6/css/all.css" rel="stylesheet" />--%>
<link href="~/js/mdi-font/css/materialdesignicons.min.css" rel="stylesheet" />
<link href="~/js/vuetify_ez.css" rel="stylesheet" />
<link href="~/js/sweetalert2/sweetalert2.min.css" rel="stylesheet" />
<link href="~/admin/Templates/TBS5ADM001/css/Style.css" rel="stylesheet" />
<link href="~/admin/item/css/floating.css" rel="stylesheet" />
<link href="~/admin/item/css/tablet-design.css" rel="stylesheet" />
</head>
<body>
<form id="form1" runat="server">
<div class="d-flex overflow-hidden" style="height:1920px">
<div id="printArea" style="width: 100vw; height: 100vh">
<%-- <div class="tablet-paper">
</div>--%>
<%-- </div>--%>
</div>
</div>
<div id="customMenu" style="display: none; position: absolute; background-color: #f9f9f9; border: 1px solid #ccc; padding: 10px; z-index: 1000;opacity:1;">
<div class="container">
<div class="row">
<div class="col-6">
<div class="form-floating mb-3">
<input type="text" id="textX" class="form-control form-control-sm mb-2" onchange="Printer.changeLocation()" />
<label class="small" for="textX">X軸位置</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="text" id="textY" class="form-control form-control-sm mb-2" onchange="Printer.changeLocation()" />
<label class="small" for="textY">Y軸位置</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="text" id="fontSize" class="form-control form-control-sm mb-2" onchange="Printer.changeSize()" />
<label class="small" for="fontSize">字體大小</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="text" id="textWidth" class="form-control form-control-sm mb-2" onchange="Printer.changeWidth()" />
<label class="small" for="textWidth">文字寬度</label>
</div>
</div>
</div>
</div>
</div>
</form>
</body>
<script src="<%=ResolveUrl("~/js/bootstrap5/js/bootstrap.bundle.min.js")%>"></script>
<script src="<%=ResolveUrl("~/js/jquery-4.0.0.min.js")%>"></script>
<script src="<%=ResolveUrl("~/js/vue.min.js")%>"></script>
<script src="<%=ResolveUrl("~/js/vuetify.min.js")%>"></script>
<script src="<%=ResolveUrl("~/js/axios.min.js")%>"></script>
<script src="<%=ResolveUrl("~/js/moment.min.js")%>"></script>
<script src="<%=ResolveUrl("~/js/sweetalert2/sweetalert2.all.min.js") %>"></script>
<script src="<%=ResolveUrl("~/admin/Templates/TBS5ADM001/js/Script.js")%>"></script>
<script src="<%=ResolveUrl("~/admin/item/jquery-ui/jquery-ui.min.js")%>"></script>
<script>
const Printer = {
selected:null,
http_host: "",
allStyle: [],
allSize: [],
allStyleDetails:[],
printData: [],
tabletElement: [],
bg: [
{ name: "黃1", path: "../../admin/print/html/tablet-1.svg" },
{ name: "黃2", path: "../../admin/print/html/tablet-1B.svg" },
{ name: "紅1", path: "../../admin/print/html/tablet-2.svg" },
{ name: "紅2", path: "../../admin/print/html/tablet-2B.svg" }
],
async init() {
console.log("init");
let HTTP_HOST = "<%=UrlHost()%>";
this.http_host = HTTP_HOST;
await Promise.all([
this.getPaperSize(),
this.getTabletElement(),
this.getTabletStyles(),
this.getAllStyleDetails()
]);
this.getData();
},
async getAllStyleDetails() {
await axios
.post(this.http_host + 'api/tablet/GetStyleDetailData', {})
.then(response => {
if (response.status == "200") {
let data = response.data;
if (data.result == "Y") {
let details = data.data;
this.allStyleDetails = details;
console.log(data.data);
}
}
}
);
},
async getPaperSize() {
let self = this
await axios
.post(this.http_host + 'api/tablet/GetPaperSize', {})
.then(response => {
//if (response.result=="Y") {
if (response.status == "200") {
let data = response.data;
this.allSize = data.data;
}
}
)
},
async getTabletElement() {
await axios
.post(this.http_host + 'api/tablet/GetTabletElement', {})
.then(response => {
//if (response.result=="Y") {
if (response.status == "200") {
let data = response.data;
this.tabletElement = data.data;
}
}
);
},
async getTabletStyles() {
await axios
.post(this.http_host + 'api/tablet/GetStyleData', {})
.then(response => {
//if (response.result=="Y") {
if (response.status == "200") {
let data = response.data;
this.allStyle = data.data;
}
}
);
},
async getData() {
let list = localStorage.getItem("list")
let param = [];
let data = JSON.parse(list)
data.forEach(x => {
param.push({ order_no: x.order_no, num: x.num });
});
await axios
.post(this.http_host + 'api/orderdetail/GetDetailToPrint', { param: param })
.then(response => {
if (response.status == 200) {
this.printData = response.data;
this.render();
this.print();
}
});
},
render() {
let self = this;
this.printData.forEach(x => {
let style = this.allStyle.find(y => y.styleID == x.style);
console.log("style:",style);
let size = this.allSize.find(y => y.paperID == style.paperSize);
let canvas = $(` <div class="canvas-area flex-grow-1 overflow-auto d-flex flex-column align-items-center position-relative" ></div>`)
let tabletpaper = $(` <div class="tablet-paper">
</div>`)
let img = self.bg.find(y=>y.name==style.backendImg);
tabletpaper.css({
"background-color": "white",
width: size.width + 'mm',
height:size.height + 'mm',
position: "absolute",
"background-image": `url(${img.path})`, 'background-size': '100% 100%',
});
let tablet = JSON.parse(x.f_num_tablet);
let mid_items = tablet.mid_items;
let left_items = tablet.left_items;
console.log("mid_items:",mid_items)
let details = this.allStyleDetails.filter(y => y.styleID == x.style);
let mid = [];
mid_items.forEach(y => {
mid.push(y.fam_name);
});
details.forEach(d => {
if (d.isActive != "hidden") {
console.log(d);
let html="";
if (d.elementID = 'title1') {
let $namelist = $(`<div class='nameList'></div>`).css({
"writing-mode": "vertical rl",
display: "flex",
"flex-direction": "row",
"flex-wrap": "wrap",
margin: "auto",
width: `${d.width}px`,
height: `${d.height}px`,
border: "0px solid #ccc",
padding: "1px",
"font-family": "BiauKai",
"letter-spacing": "0.1em",
"column-gap": "1px",
"row-gap": "1px",
"align-items": "center",
});
mid.forEach(z => {
let $span = $(`<span>${z}</span>`).css({
display: "block",
"min-height": `${d.textHeight}px`,
"max-height": `${d.height}px`,
width: `${d.textWidth}px`,
"text-align": "justify",
"text-align-last": "justify",
"margin-bottom": "40px",
"margin-left": "5px",
"text-justify": "inter-character",
"z-index": 10000,
});
$namelist.append($span);
});
html = $namelist;
}
let content = $(`<div class="tablet-element vertical-text "></div>`)
.css({
position: "absolute", left: d.startX + "mm", top: d.startY + "mm", fontSize: d.fontSize + 'pt', fontFamily: d.fontFamily, "z-index": 9999, visibility: d.isActive
//position: "absolute", left: el.startX + "mm", top: el.startY + "mm", fontSize: el.fontSize + 'pt', fontFamily: el.fontFamily, "z-index": 9999, visibility: el.isActive
})
.html(html);
tabletpaper.append(content);
}
})
$(canvas).append(tabletpaper);
$("#printArea").append(canvas);
//this.bindKeyEvent();
});
$(".tablet-element").draggable({
start(e, ui) {
console.log("gogogogo");
},
stop(e, ui) {
console.log(ui.position.left, ui.position.top);
}
});
$(".tablet-element").on("click", function (e) {
e.preventDefault();
console.log(this);
self.selected = $(this);
let fontSize = $(this).css("fontSize");
let fontFamily = $(this).css("fontFamily");
let left = $(this).css("left");
let top = $(this).css("top");
console.log(fontSize, fontFamily, left, top);
});
$(".tablet-element").on("contextmenu", function (e) {
e.preventDefault();
console.log(this);
self.selected = $(this);
let fontSize = $(this).css("fontSize");
let fontFamily = $(this).css("fontFamily");
let left = $(this).css("left");
let top = $(this).css("top");
console.log(fontSize, fontFamily, left, top);
$("#customMenu").css({
top: e.pageY + "px",
left: (e.pageX+30) + "px"
});
left = left.replace("px", "");
top = top.replace("px", "");
$("#textX").val(self.fix2(left*0.265));
$("#textY").val(self.fix2(top * 0.265));
$("#fontSize").val(fontSize);
//$("#textWidth").val("");
// Show the custom div
$("#customMenu").show();
});
},
fix2(val) {
return Number.parseFloat(val).toFixed(2);
},
async changeLocation() {
console.log(this.selected);
$(this.selected).css("left", $("#textX").val()+"mm");
$(this.selected).css("top", $("#textY").val()+"mm");
},
async changeSize() {
$(this.selected).css("fontSize", $("#fontSize").val())
},
async changeWidth() {
let nameList = $(this.selected).find(".nameList").first();
console.log("nameList:", nameList);
if (nameList) {
let spans = $(nameList).find("span");
console.log(spans);
if (spans) {
spans.each(function(index,x) {
$(x).css("width",$("#textWidth").val())
});
}
}
},
print() {
//let s = this.allStyle.find(x => x.styleID == this.styleID)
let size = this.allSize.find(x => x.paperID = "0001")
let w = window.open('', '_blank');
if (!w) {
alert("請允許瀏覽器開啟彈出式視窗!");
return;
}
// 1. 抓取您原本網頁定義的 HTTP_HOST (您的全域變數),如果沒有則抓取當前網址
let hostUrl = typeof this.http_host !== 'undefined' ? this.http_host : (window.location.protocol + "//" + window.location.host);
if (!hostUrl.endsWith('/')) hostUrl += '/';
// 2. 抓出畫布完整的 HTML
let canvasHtml = $("#printArea").html();
// 3. 【關鍵修復】把所有的 "../../" 替換成完整的網址,解決底圖破圖問題!
canvasHtml = canvasHtml.replace(/\.\.\/\.\.\//g, hostUrl);
// 4. 組合列印視窗的 HTML
let htmlContent = `
<!DOCTYPE html>
<html>
<head>
<title>預覽列印 - 牌位設計</title>
<meta charset="utf-8">
<style>
/* 名單金字塔佈局容器 */
.roster-container {
width: 100%; height: 100%;
writing-mode: vertical-rl; /* 直書 */
display: flex;
/*flex-direction: column;*/ /* 雖然是直書,但物理上我們是將「上層區」和「下層區」垂直堆疊 */
flex-direction: row; /* 上下分層 (Top / Bottom) */
align-items: center; /* 左右置中對齊 */
justify-content: center;
gap: 20px; /* 這是「上層」跟「下層」之間的距離,可以設大一點 */
}
.roster-row {
display: flex;
flex-direction: row-reverse; /* 直書由右至左,所以 Row 要反向或依需求調整 */
justify-content: center;
gap: 8px; /* 名字之間的間距 */
margin-left: 10px; /* 上下排之間的間距 (因為是直書margin-left 是物理上的左邊/下方) */
}
.name-group {
display: flex;
flex-direction: column; /* ★★★ 關鍵:這讓名字左右並排 ★★★ */
justify-content: center;
align-items: center;
/* gap 由 HTML 動態綁定 */
}
.roster-name {
text-orientation: upright;
/*font-weight: bold;*/
white-space: nowrap;
line-height: 1.2;
font-family: 'Kaiti', serif;
/* 確保名字本身不會佔據過多寬度導致間距看起來很大 */
width: fit-content;
}
.vertical-text {
writing-mode: vertical-rl !important;
-webkit-writing-mode: vertical-rl !important;
text-orientation: mixed !important;
}
/* 【修復底圖沒出現】強制印出背景設定 */
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
color-adjust: exact !important;
}
/* 【修復排版沒照設定】覆寫原本 HTML 裡的 fixed並防止 Bootstrap 洗掉 absolute */
.tablet-paper {
position: relative !important;
margin: 0 auto !important;
page-break-after: always !important;
box-shadow: none !important;
width: var(--page-w);
height: var(--page-h);
}
.tablet-element {
position: absolute !important; /* 絕對不能被 Bootstrap 覆蓋為 static */
color: black !important; /* 確保文字是黑色的 */
}
.ancestor-wrapper {
/* 重置為橫向流,這樣 column 才會是真正的上下堆疊 */
writing-mode: horizontal-tb;
display: flex;
flex-direction: column;
align-items: center; /* 水平置中 */
justify-content: center;
width: fit-content;
}
.main-name {
line-height: 1.2;
/* 保持大字 */
}
.sub-text {
font-size: 0.6em; /* 縮小字體 */
line-height: 1.2;
margin-top: 4px; /* 與上方林張的間距 */
white-space: nowrap; /* 避免自動換行 */
writing-mode:vertical-rl
}
/* 列印時的紙張大小與頁面歸零 */
@media print {
@page {
/* 動態套用您設定的紙張寬高 */
size: ${size.width}mm ${size.height}mm portrait;
margin: 0;
}
body, html {
margin: 0 !important;
padding: 0 !important;
}
body{
--page-w: ${size.width}mm;
--page-h: ${size.height}mm;
--font-max: 22pt;
--bg-padding: 0;
}
}
</style>
</head>
<body>
${canvasHtml}
</body>
</html>
`;
w.document.write(htmlContent);
w.document.close();
// 5. 將等待時間稍微拉長至 1.2 秒,確保大張的 SVG 底圖與外部字體(如標楷體)下載完畢
setTimeout(() => {
w.focus();
w.print();
}, 1200);
},
//bindKeyEvent() {
// let element = document.querySelectorAll(".tablet-element");
// element.forEach(y => {
// console.log("QQ:",y);
// $(y).on("keydown", (e) => {
// console.log(e.key);
// e.preventDefault();
// let top = parseInt(y.style.top);
// let left = parseInt(y.style.left);
// switch (e.key) {
// case 'ArrowUp': top = top - 10; break;
// case 'ArrowDown': top = top + 10; break;
// case 'ArrowLeft': left = left - 10; break;
// case 'ArrowRight': left = left + 10; break;
// }
// y.style.top = top + 'px';
// y.style.left = left + 'px';
// })
// })
//}
}
$(document).click(function (e) {
if (!$("#customMenu").is(e.target) && $("#customMenu").has(e.target).length === 0) {
$("#customMenu").hide();
}
});
$(() => Printer.init());
</script>
</html>