Files
17168ERP/web/admin/item/TabletDesigner.aspx
2026-03-10 17:59:57 +08:00

786 lines
38 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="TabletDesigner.aspx.cs" Inherits="admin_item_TabletDesigner" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" %>
<%@ Register Src="~/admin/_uc/alert.ascx" TagPrefix="uc1" TagName="alert" %>
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" runat="Server">
<%-- <style type="text/css">
@import "css/styles.css";
@import "css/tablet-design.css";
@import "css/floating.css";
</style>--%>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<div class="d-flex overflow-hidden">
<div class="p-2 bg-dark text-white floting-box" style="width: 250px; left: 20px; top: 80px;">
<h6 class="border-bottom pb-2">設計工具箱</h6>
<div class="input-group mb-3">
<button class="btn btn-outline-secondary dropdown-toggle" type="button"
data-bs-toggle="dropdown" aria-expanded="false">
版型</button>
<ul class="dropdown-menu style-menu">
<li><span class="dropdown-item" data-value="">選擇版型</span></li>
</ul>
<input type="text" id="styleName" class="form-control" aria-label="版型名稱">
</div>
<div class="form-floating mb-3">
<select class="form-select form-select-sm mb-2 " onchange="Designer.changePaper()" id="paperSize">
<option value="">請選擇</option>
</select>
<label for="paperSize" style="color: black">尺寸</label>
</div>
<div id="sizeDiv" style="display:none;">
<div class="form-floating mb-3">
<input type="text" class="form-control form-select-sm mb-2 " id="paperName" />
<label for="paperName" style="color: black">名稱</label>
</div>
<div class="form-floating mb-3">
<input type="text" class="form-control form-select-sm mb-2 " id="paperWidth" />
<label for="paperWidth" style="color: black">寬度</label>
</div>
<div class="form-floating mb-3">
<input type="text" class="form-control form-select-sm mb-2 " id="paperHeight" />
<label for="paperHeight" style="color: black">高度</label>
</div>
<div class="row">
<span class="btn btn-info" onclick="Designer.savePaperSize()">儲存</span>
</div>
</div>
<div id="paperOrientation" onclick="Designer.changeOrientation()" class="mb-2">
<span></span>
</div>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('address')">地址欄</span>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('title1')">牌位正名</span>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('lefttitle')">左正名</span>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('righttitle')">右正名</span>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('titletriangle')">品字名單</span>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('combined')">雙姓合併置中</span>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('tricombined')">三姓合併置中</span>
<span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.displayItem('alive')">陽上報恩</span>
<div class="form-floating mb-3">
<%-- <span class="btn btn-sm btn-outline-light w-100 mb-2" onclick="Designer.clickBackend()">
<i class="bi bi-upload me-1"></i>上傳自訂底圖 (PNG/JPG)
</span>--%>
<select class="form-select form-select-sm mb-2 " onchange="Designer.changeBg()" id="backendInp">
<option value="">請選擇</option>
</select>
<label for="backendInp" style="color: black">選用底圖</label>
<%-- <input id="backendInp" type="file" accept="image/png, image/jpeg,image/svg+xml" style="display: none">--%>
</div>
<hr>
<div class="form-floating mb-3">
<select class="form-select form-select-sm mb-2 " onchange="Designer.changePrintSize()" id="printSize">
<option value="">請選擇</option>
</select>
<label for="printSize" style="color: black">列印尺寸</label>
</div>
<div class="form-floating mb-3">
<select class="form-select form-select-sm mb-2 " onchange="Designer.changePrintMode()" id="printMode">
<option value="">請選擇</option>
<option value="combine">合併</option>
<option value="origin">原尺寸</option>
</select>
<label for="printMode" style="color: black">列印模式</label>
</div>
<div class="form-floating mb-3">
<input type="number" id="perpage" class="form-control form-control-sm mb-2">
<label class="small" for="perpage" style="color: black;">每頁列印筆數</label>
</div>
<div class="row">
<div class="col-6">
<span class="btn btn-sm btn-outline-info w-100 mb-2" onclick="Designer.saveStyle()">存檔</span>
</div>
<div class="col-6">
<%-- <span class="btn btn-sm btn-outline-info w-100 mb-2" onclick="">存檔</span>--%>
</div>
</div>
</div>
<div class="canvas-area flex-grow-1 overflow-auto d-flex flex-column align-items-center position-relative" id="canvas">
<div class="tablet-paper">
<%--<div class="tablet-element vertical-text">嘿嘿</div>--%>
</div>
</div>
<div id="attr-box" class="d-none p-2 bg-dark text-whit floting-box" style="top: 80px; right: 20px">
<div class="form-floating mb-3">
<textarea id="inp-text" class="form-control form-control-sm mb-2" rows="5"></textarea>
<label class="small" for="inp-text">內容文字</label>
</div>
<div class="form-floating mb-3">
<input type="number" id="inp-size" class="form-control form-control-sm mb-2">
<label class="small" for="inp-size">字體大小 (pt)</label>
</div>
<div class="row ">
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="2offset" class="form-control form-control-sm mb-2">
<label class="small" for="2offset">二行偏移量</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="3offset" class="form-control form-control-sm mb-2">
<label class="small" for="3offset">三行偏移量</label>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="4offset" class="form-control form-control-sm mb-2">
<label class="small" for="4offset">四行偏移量</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="breakLen" class="form-control form-control-sm mb-2">
<label class="small" for="breakLen">斷行字數</label>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="xPosition" class="form-control form-control-sm mb-2">
<label class="small" for="xPosition">X</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="yPosition" class="form-control form-control-sm mb-2">
<label class="small" for="yPosition">Y</label>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="width" class="form-control form-control-sm mb-2">
<label class="small" for="width">寬度</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="height" class="form-control form-control-sm mb-2">
<label class="small" for="height">高度</label>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="textWidth" class="form-control form-control-sm mb-2">
<label class="small" for="textWidth">文字寬度</label>
</div>
</div>
<div class="col-6">
<div class="form-floating mb-3">
<input type="number" id="textHeight" class="form-control form-control-sm mb-2">
<label class="small" for="textHeight">文字高度</label>
</div>
</div>
</div>
</div>
</div>
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="footer_script" runat="Server">
<%-- <div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">紙張尺寸設定</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<input type="text" id="PaperName" />
</div>
<div class="col-12">
<input type="text" id="PaperWidth" />
</div>
<div class="col-12">
<input type="text" id="PaperHeight" />
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>--%>
<%-- <script src="../../js/jquery-4.0.0.min.js"></script>
<script src="jquery-ui/jquery-ui.js"></script>--%>
<script>
const Designer = {
elements: [],
activeId: null,
styleID: null,
paper: { width: 100, height: 272 },
rosterLimit: 8,
allSize: [
//{ name: "A3", width: 297, height: 420, selected: "" },
//{ name: "A4", width: 210, height: 297, selected: "" },
//{ name: "B4", width: 257, height: 364, selected: "" },
//{ name: "red", width: 100, height: 272, selected: "selected" },
],
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" }
],
allStyle: [
],
tabletElements: [
],
orientation: "portrait",
init() {
//$(".tablet-element").draggable({});
this.getPaperSize();
this.getElements();
this.getStyles();
this.bindEvents();
//this.loadConfig();
this.bindBackend();
this.bg.forEach(x => {
$("#backendInp").append("<option value='" + x.name + "'>" + x.name + "</option>")
});
$("#paperOrientation").html("<span>直向</span>")
},
changeOrientation() {
this.orientation = (this.orientation === "portrait" ? "land" : "portrait");
$("#paperOrientation").empty();
let ori = this.orientation == "portrait" ? "直向" : "橫向";
$("#paperOrientation").html("<span>" + ori + "</span>");
let paperSize = $("#paperSize").val()
let size = this.allSize.find(x => x.name == paperSize)
this.paper.width = this.orientation == "portrait" ? size.width : size.height;
this.paper.height = this.orientation == "portrait" ? size.height : size.width;
$(".tablet-paper").css({
"background-color": "white",
width: this.paper.width + "mm",
height: this.paper.height + "mm",
});
},
async getPaperSize() {
let self = this
await axios
.post(HTTP_HOST + 'api/tablet/GetPaperSize', {})
.then(response => {
//if (response.result=="Y") {
if (response.status == "200") {
let data = response.data;
if (data.result == "Y") {
data.data.forEach(x => {
self.allSize.push({ name: x.paperName, id: x.paperID, width: x.width, height: x.height })
});
}
}
});
$("#paperSize").append("<option value='newsize' >新增尺寸</option>")
this.allSize.forEach(x => {
$("#paperSize").append("<option value='" + x.name + "' " + x.selected + ">" + x.width + "*" + x.height + "</option>")
$("#printSize").append("<option value='" + x.name + "' " + x.selected + ">" + x.width + "*" + x.height + "</option>");
})
},
async getElements() {
let self = this
await axios
.post(HTTP_HOST + 'api/tablet/GetTabletElement', {})
.then(response => {
//if (response.result=="Y") {
if (response.status == "200") {
let data = response.data;
if (data.result == "Y") {
data.data.forEach(x => {
self.tabletElements.push(x);
});
}
}
});
},
async getStyles() {
await axios
.post(HTTP_HOST + 'api/tablet/GetStyleData', {})
.then(response => {
//if (response.result=="Y") {
if (response.status == "200") {
let data = response.data;
if (data.result == "Y") {
data.data.forEach(x => {
this.allStyle.push(x);
$(".style-menu").append("<li><span class='dropdown-item style-item' data-value='" + x.styleID + "'>" + x.name + "</span></li>");
});
this.bindDropdown();
}
}
//}
});
},
bindDropdown() {
let self = this;
$(".style-menu li").on("click", function (e) {
$(".style-menu li").removeClass('active');
$(this).addClass('active');
$("#styleName").val(e.target.textContent);
self.styleID = e.target.getAttribute("data-value")
self.changeStyle(e.target.getAttribute("data-value"));
let style = self.allStyle.find(x => x.styleID == e.target.getAttribute("data-value"));
let size = self.allSize.find(x => x.name == style.paperSize);
self.paper.width = size.width;
self.paper.height = size.height;
});
},
async changeStyle(id) {//切換版型,抓回明細
let self = this;
this.elements.length = 0;
let obj = this.elements
let s = this.allStyle.find(x => x.styleID == id)
$("#paperSize").val(s.paperSize);
$("#backendInp").val(s.backendImg);
$("#printSize").val(s.printSize);
$("#printMode").val(s.printMode);
$("#perPage").val(s.printPageCount);
let img = this.bg.find(x => x.name == s.backendImg);
$(".tablet-paper").css({ 'background-image': 'url(' + (img ? img.path : "") + ')', 'background-size': '100% 100%' })
await axios
.post(HTTP_HOST + 'api/tablet/GetStyleDetailData', { styleID: id })
.then(response => {
if (response.status == "200") {
let data = response.data;
if (data.result == "Y") {
let details = data.data;
$(".tablet-paper").empty()
details.forEach(el => {
let te = self.tabletElements.find(x => {
return x.elementID == el.elementID
});
//console.log("details:",el,te);
let config = {
id: el.elementID,
type: te.elementType,
text: te.sampleContent.replaceAll("\\n", "\n"),
x: el.startX, y: el.startY,
style: {
fontSize: el.fontSize,
fontFamily: "Kaiti",
isVertical: true,
letterSpacing: 5, lineHeight: 1.5,
visibility: el.isActive,
},
width: el.width,
height: el.height,
textWidth: el.textWidth,
textHeight: el.textHeight,
breakLen: el.breakLen,
backendInp: el.backendImg
};
obj.push(config)
})
this.render();
}
}
});
},
changeBg() {
let path = this.bg.find(el => el.name == $("#backendInp").val())
$(".tablet-paper").css({ 'background-image': 'url(' + path.path + ')', 'background-size': '100% 100%' })
},
changePaper() {
let paperSize = $("#paperSize").val()
console.log(paperSize);
if (paperSize == "newsize") {
$("#sizeDiv").attr("style","display:");
} else {
let size = this.allSize.find(x => x.name == paperSize)
$(".tablet-paper").css({
"background-color": "white",
width: size.width + "mm",
height: size.height + "mm",
});
}
},
async savePaperSize() {
let ps = {
paperName: $("#paperName").val(),
width: $("#paperWidth").val(),
height: $("#paperHeight").val()
}
console.log(ps);
await axios
.post(HTTP_HOST + 'api/tablet/SavePaperSize', ps)
.then(response => {
if (response.status == "200") {
}
});
},
changePrintMode() {
},
bindEvents() {
// 文字變更連動渲染
$('#inp-text').on('input', (e) => this.updateActive('text', $(e.target).val()));
$('#inp-size').on('input', (e) => this.updateActive('fontSize', $(e.target).val()));
$('#width').on('input', (e) => this.updateActive('width', $(e.target).val()))
$('#2offset').on('input', (e) => this.updateActive('2offset', $(e.target).val()))
$('#3offset').on('input', (e) => this.updateActive('3offset', $(e.target).val()))
$('#4offset').on('input', (e) => this.updateActive('4offset', $(e.target).val()))
$('#breakLen').on('input', (e) => this.updateActive('breakLen', $(e.target).val()))
$('#width').on('input', (e) => this.updateActive('width', $(e.target).val()))
$('#height').on('input', (e) => this.updateActive('height', $(e.target).val()))
$('#textWidth').on('input', (e) => this.updateActive('textWidth', $(e.target).val()))
$('#textHeight').on('input', (e) => this.updateActive('textHeight', $(e.target).val()))
$(document).on('mousedown', '.tablet-element', (e) => {
e.stopPropagation();
this.select($(e.currentTarget).attr('id'));
});
},
loadConfig() {
$.ajax({
type: "POST", url: "TabletDesigner.aspx/GetConfig", contentType: "application/json",
success: (res) => {
const data = JSON.parse(res.d);
this.elements = data.elements;
this.render();
}
});
},
// 處理分頁渲染邏輯
render() {
$(".tablet-paper").empty();
//const $canvas = $('#canvas').empty();
const roster = this.elements.find(e => e.type === 'roster');
const names = roster ? roster.text.split('\n').filter(s => s.trim()) : [];
const pages = Math.max(1, Math.ceil(names.length / this.rosterLimit));
//for (let p = 0; p < pages; p++) {
// const $paper = $('<div class="tablet-paper"></div>')
// .css({ "background-color": "red", width: this.paper.width + 'mm', height: this.paper.height + 'mm' });
let $paper = $(".tablet-paper").css({ "background-color": "white", width: this.paper.width + 'mm', height: this.paper.height + 'mm', position: "absolute" });
//const slice = names.slice(p * this.rosterLimit, (p + 1) * this.rosterLimit);
const slice = names.slice(0 * this.rosterLimit, (0 + 1) * this.rosterLimit);
this.elements.forEach(el => {
console.log("shit:", el);
$paper.append(this.createEl(el, slice));
});
//$canvas.append($paper);
//}
//let s = this.allStyle.find(x => x.styleID == this.styleID);
//let d = this.elements.filter(x => x.styleID == this.styleID);
//console.log(s,d);
this.makeDraggable();
},
createEl(el, slice) {
let html = '';
// 1. 智慧名單渲染
if (el.type === 'roster') {
html = this.renderRoster(slice, el);
}
// 2. 正名合併置中
else if (el.type === 'combined-center') {
const parts = el.text.split('\n');
html = `<div class="ancestor-wrapper" >
<span class="main-name" >${parts[0] || ''}</span>
<span class="sub-text">${parts[1] || ''}</span>
</div>`;
}
// 3. 地址數字轉橫排
else if (el.id === 'address') {
html = el.text.replace(/(\d+)/g, '<span class="tate-chu-yoko">$1</span>');
}
else if (el.id === 'title1') {
html = this.renderNameList(slice, el);
console.log(html);
}
else {
html = el.text;
}
console.log("QQ:", el);
return $(`<div class="tablet-element vertical-text ${this.activeId === el.id ? 'selected' : ''}" id="${el.id}"></div>`)
.css({
position: "absolute", left: el.x + "mm", top: el.y + "mm", fontSize: el.style.fontSize + 'pt', fontFamily: el.style.fontFamily, "z-index": 9999, visibility: el.style.visibility
//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);
},
renderNameList(names, el) {
let $namelist = $(`<div class='nameList'></div>`).css({
"writing-mode": "vertical rl",
display: "flex",
"flex-direction": "row",
"flex-wrap": "wrap",
margin: "auto",
width: `${el.width}px`,
height: `${el.height}px`,
border: "0px solid #ccc",
padding: "1px",
"font-family": "BiauKai",
"letter-spacing": "0.1em",
"column-gap": "1px",
"row-gap": "1px",
"align-items": "center",
});
console.log("nameList:", $namelist)
let self = this;
names.forEach(n => {
$namelist.append(self.renderNameSpan(n, el))
})
return $namelist;
},
renderNameSpan(name, el) {
return $(`<span>${name}</span>`).css({
display: "block",
"min-height": `${el.textHeight}px`,
"max-height": `${el.height}px`,
width: `${el.textWidth}px`,
"text-align": "justify",
"text-align-last": "justify",
"margin-bottom": "40px",
"margin-left": "5px",
"text-justify": "inter-character",
});
},
// 品字佈局邏輯:一上二下
renderRoster(names, el) {
if (!names.length) return '';
const mid = names.length === 1 ? 1 : Math.floor(names.length / 2);
const top = names.slice(0, mid);
const bot = names.slice(mid);
const size = this.autoScale(names, el.fontSize);
let h = `<div class="roster-container" style="gap:${el.style.itemSpacing || 20}px">`;
h += `<div class="name-group">${top.map(n => `<div class="roster-name" style="font-size:${size}pt">${n}</div>`).join('')}</div>`;
if (bot.length) h += `<div class="name-group">${bot.map(n => `<div class="roster-name" style="font-size:${size}pt">${n}</div>`).join('')}</div>`;
return h + `</div>`;
},
autoScale(names, base) {
const max = Math.max(...names.map(n => n.length), 0);
return max > 5 ? Math.max(base * (5 / max), base * 0.6) : base;
},
getPosInMm(px) {
return parseFloat((px * 25.4 / 96).toFixed(2));
},
// 拖動後同步所有頁面的位置
makeDraggable() {
const self = this;
$(".tablet-element").draggable({
start(e, ui) {
console.log("gogogogo");
},
stop(e, ui) {
const id = $(this).attr('id');
const el = self.elements.find(x => x.id === id);
el.x = self.getPosInMm(ui.position.left);
el.y = self.getPosInMm(ui.position.top);
//console.log(id,ui.position.left, ui.position.top,ui.offset.left,ui.offset.top);
$(`.tablet-element[id="${id}"]`).css({ left: el.startX + "mm", top: el.startY + "mm" });
}
});
},
select(id) {
this.activeId = id;
const el = this.elements.find(x => x.id === id);
$('#attr-box').removeClass('d-none');
$('#inp-text').val(el.text);
$('#inp-size').val(el.style.fontSize);
$('#xPosition').val(el.x);
$("#yPosition").val(el.y);
$('#2offset').val(el.twoOffset);
$("#3offset").val(el.threeOffset);
$("#4offset").val(el.fourOffset);
$("#breakLen").val(el.breakLen);
$("#width").val(el.width);
$("#height").val(el.height);
$("#textWidth").val(el.textWidth);
$("#textHeight").val(el.textHeight);
//this.render();
},
updateActive(key, val) {
const el = this.elements.find(x => x.id === this.activeId);
if (key === 'fontSize') el.fontSize = parseFloat(val);
else if (key === 'width') el.width = parseFloat(val);
else if (key === 'breakLen') el.breakLen = parseInt(val);
else if (key === '2offset') el.twoOffset = parseFloat(val);
else if (key === '3offset') el.threeOffset = parseFloat(val);
else if (key === '4offset') el.fourOffset = parseFloat(val);
else el[key] = val;
if (el.type == "roster") {
const names = el.text.split('\n').filter(s => s.trim());
$(`.tablet-element[id="${this.activeId}"]`).css({
position: "absolute", left: el.startX + "mm", top: el.startY + "mm", fontSize: el.fontSize + 'pt', fontFamily: el.fontFamily, "z-index": 9999, visibility: el.style.isActive
}).html(this.renderRoster(names.slice(0 * this.rosterLimit, (0 + 1) * this.rosterLimit), el));
} else if (el.type == "combined-center") {
const parts = el.text.split('\n');
html = `<div class="ancestor-wrapper" >
<span class="main-name" >${parts[0] || ''}</span>
<span class="sub-text">${parts[1] || ''}</span>
</div>`;
$(`.tablet-element[id="${this.activeId}"]`).css({
position: "absolute", left: el.startX + "mm", top: el.startY + "mm", fontSize: el.fontSize + 'pt', fontFamily: el.fontFamily, "z-index": 9999, visibility: el.style.isActive
}).html(html);
} else if (this.activeId === "title1") {
let slice = el.text.split('\n').filter(s => s.trim());
//html = "<div class='name-list'>";
//console.log(slice);
//slice.forEach(x => {
// html = html + "<span>" + x + "</span>"
//});
//html = html + "</div>";
html = this.renderNameList(slice, el);
$(`.tablet-element[id="${this.activeId}"]`).css({
position: "absolute", left: el.x + "mm", top: el.y + "mm", fontSize: el.style.fontSize + 'pt', fontFamily: el.style.fontFamily, "z-index": 9999, visibility: el.style.visibility
}).html(html);
} else {
$(`.tablet-element[id="${this.activeId}"]`).css({
position: "absolute", left: el.x + "mm", top: el.y + "mm", fontSize: el.style.fontSize + 'pt', fontFamily: el.style.fontFamily, "z-index": 9999, visibility: el.style.visibility
}).text(el.text);
}
//this.render();
},
displayItem(id) {
let el = this.elements.find(x => x.id === id);
el.style.visibility = el.style.visibility === "hidden" ? "" : "hidden";
$("#" + id).css({
position: "absolute", left: el.x + "mm", top: el.y + "mm", fontSize: el.style.fontSize + 'pt', fontFamily: el.style.fontFamily, "z-index": 9999, visibility: el.style.visibility
})
},
addMulti(prefix, count) {
for (let i = 1; i <= count; i++) {
const id = `${prefix}-${Date.now()}-${i}`;
this.elements.push({
id, type: 'title', text: `正名${i}`, x: 100 - (i * 30), y: 80,
style: { fontSize: 24, fontFamily: 'Kaiti', isVertical: true }
});
}
//this.render();
},
addCombined() {
this.stopPropagation();
this.elements.push({
id: 'combined-' + Date.now(), type: 'combined-center', text: '林張\n氏歷代祖先', x: 130, y: 80,
style: { fontSize: 24, fontFamily: 'Kaiti', isVertical: true }
});
//this.render();
},
addElement() {
//console.log("QQQ");
},
wrapImageInSvg(imageBase64) {
// 建立一個簡單的 SVG 字串,將圖片鋪滿
// preserveAspectRatio="none" 確保圖片會拉伸填滿 SVG 容器
const svgString = `
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" preserveAspectRatio="none">
<image href="${imageBase64}" x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" />
</svg>
`.trim();
// 轉成 Data URI 格式
// 注意SVG 內容若包含特殊字元需編碼,但 base64 圖片通常是安全的
// 為了保險,我們使用 encodeURIComponent 對 svgString 編碼
return `data:image/svg+xml;utf8,${encodeURIComponent(svgString)}`;
},
clickBackend() {
$("#backendInp").click();
},
bindBackend() {
$("#backendInp").on('change', function (e) {
const input = e.target;
if (input.files && input.files[0]) {
const file = input.files[0];
// 1. 先讀取檔案轉成 Base64
const reader = new FileReader();
reader.onload = (e) => {
const base64Image = e.target.result; // 這會是 data:image/png;base64,xxxx...
// 2. 將 Base64 PNG 包裝成 SVG
//const svgDataUri = this.wrapImageInSvg(base64Image);
// 3. 設定到底圖
//this.service.setBackground(svgDataUri);
$(".tablet-paper").css({ 'background-image': 'url(' + base64Image + ')', 'background-size': '100% 100%' })
};
reader.readAsDataURL(file);
}
})
},
async saveStyle() {
let detail = [
];
this.elements.forEach((el) => {
detail.push({
elementID: el.id, startX: el.x.toString(), startY: el.y.toString(), fontSize: el.style.fontSize, fontFamily: el.style.fontFamily,
breakLen: el.breakLen, twoOffset: el.twoOffset, threeOffset: el.threeOffset, fourOffset: el.fourOffset,
isActive: el.style.visibility, width: el.width, height: el.height, textWidth: el.textWidth, textHeight: el.textHeight
});
});
let master = {
styleID: this.styleID, styleName: $("#styleName").val(), paperSize: $("#paperSize").val(),
backendImg: $("#backendInp").val(), printSize: $("#printSize").val(), printMode: $("#printMode").val(),
orientation: $("#paperOrientation").val(), printPageCount: $("#perpage").val(),
detail: detail
}
console.log(master);
let path = "SavDegignerData";
if (this.styleID != null && this.styleID != "") {
path = "UpdateDegignerData"
}
await axios
.post(HTTP_HOST + `api/tablet/${path}`, master)
.then(response => {
console.log(response);
});
}
};
$(() => Designer.init());
</script>
</asp:Content>