This commit is contained in:
2026-08-26 18:03:54 +08:00
parent b7ae0abc20
commit b02fc8ec52
+80 -116
View File
@@ -669,114 +669,81 @@
$("#canselectItem").empty(); $("#canselectItem").empty();
let currentData = [], editLabel = "未定義區塊"; let currentData = [], editLabel = "未定義區塊";
// 🌟 1. 判斷是否為超薦牌位 (利用 item_type === 'B' 或是依據底圖名稱防呆) let isChaojian = (this.item_type === 'B' || (typeof VueApp !== 'undefined' && VueApp.item_type === 'B') || (this.tabletItem && this.tabletItem.item_type === 'B')) ||
let isChaojian = false; (this.allStyle.find(y => y.styleID == this.selectStyle)?.name || "").includes("超薦");
if (this.item_type === 'B' || (typeof VueApp !== 'undefined' && VueApp.item_type === 'B') || (this.tabletItem && this.tabletItem.item_type === 'B')) {
isChaojian = true;
} else {
let style = this.allStyle.find(y => y.styleID == this.selectStyle);
if (style && style.name && style.name.includes("超薦")) {
isChaojian = true;
}
}
// 預設生死條件:超薦要死者(true),消災要活者(false)
let requireDeceased = isChaojian; let requireDeceased = isChaojian;
// 🌟 2. 判斷當前編輯區塊 if (element.hasClass("liveList")) { editLabel = "陽上"; currentData = this.alive; requireDeceased = false; }
if (element.hasClass("liveList")) { else if (element.hasClass("nameList") || element.hasClass("rosterList") || element.hasClass("ancestor-wrapper")) { editLabel = "正名"; currentData = this.properTitle; }
editLabel = "陽上"; else if (element.hasClass("lefttitle")) { editLabel = "左正名"; currentData = this.leftProperTitle; }
currentData = this.alive; else if (element.hasClass("righttitle")) { editLabel = "右正名"; currentData = this.rightProperTitle; }
requireDeceased = false; // 🚨 陽上永遠只能選活者 else if (element.hasClass("address")) { editLabel = "地址"; currentData = this.address ? [this.address] : []; }
}
else if (element.hasClass("nameList") || element.hasClass("rosterList") || element.hasClass("ancestor-wrapper")) {
editLabel = "正名";
currentData = this.properTitle;
}
else if (element.hasClass("lefttitle")) {
editLabel = "左正名";
currentData = this.leftProperTitle;
}
else if (element.hasClass("righttitle")) {
editLabel = "右正名";
currentData = this.rightProperTitle;
}
else if (element.hasClass("address")) {
editLabel = "地址";
currentData = this.address ? [this.address] : [];
}
$("#current-edit-label").text("目前編輯:" + editLabel); $("#current-edit-label").text("目前編輯:" + editLabel);
// 渲染已選 // 🌟 從物件中取出 fam_name 顯示
currentData.forEach((x, index) => { currentData.forEach((item, index) => {
let displayName = typeof item === 'string' ? item : item.fam_name;
$("#selectedItem").append(` $("#selectedItem").append(`
<li><span class="selected">${x}</span><div class="list-actions"> <li><span class="selected">${displayName}</span><div class="list-actions">
<button class="itemUp" data-idx="${index}">↑</button><button class="itemDown" data-idx="${index}">↓</button><button class="itemRemove" data-idx="${index}">-</button> <button class="itemUp" data-idx="${index}">↑</button><button class="itemDown" data-idx="${index}">↓</button><button class="itemRemove" data-idx="${index}">-</button>
</div></li>`); </div></li>`);
}); });
// 地址不需要出現親友選單 if (element.hasClass("address")) { this.bindListEvents(); return; }
if (element.hasClass("address")) {
this.bindListEvents();
return;
}
// 🌟 3. 渲染可選 (嚴格過濾生死狀態) // 🌟 從已選陣列取出名稱來做比對
let currentNames = currentData.map(x => typeof x === 'string' ? x : x.fam_name);
let filterKeyword = $('#filter_txt').val().trim() || ""; let filterKeyword = $('#filter_txt').val().trim() || "";
this.familyMembers.forEach(f => {
// 判斷該親友的生死狀態 (相容 boolean 與字串)
let isDead = (f.deceased === true || f.deceased === "true" || f.deceased === "True");
// 條件成立:生死符合要求 + 尚未加入 + 關鍵字相符 this.familyMembers.forEach(f => {
if (isDead === requireDeceased && !currentData.includes(f.fam_name) && f.fam_name.includes(filterKeyword)) { let isDead = (f.deceased === true || f.deceased === "true" || f.deceased === "True");
if (isDead === requireDeceased && !currentNames.includes(f.fam_name) && f.fam_name.includes(filterKeyword)) {
$("#canselectItem").append(` $("#canselectItem").append(`
<li> <li><span style="opacity:0.5">卍</span> <span class="unselect">${f.fam_name}</span>
<span style="opacity:0.5">卍</span> <span><i class="rounded-pill rounded-3 ${(f && f.fam_title) ? 'p-1' : ''}" style="background-color:lightgray">${f.fam_title ? f.fam_title : ""}</i></span>
<span class="unselect">${f.fam_name}</span> <span class='itemAppend' style="float:right;cursor:pointer;">&#43;</span></li>`);
<span>
<i class="rounded-pill rounded-3 ${(f && f.fam_title) ? 'p-1' : ''}" style="background-color:lightgray">
${f.fam_title ? f.fam_title : ""}
</i>
</span>
<span class='itemAppend' style="float:right;cursor:pointer;">&#43;</span>
</li>
`);
} }
}); });
this.bindListEvents(); this.bindListEvents();
}, },
bindListEvents() { bindListEvents() {
let self = this; let self = this;
// 🌟 修正1:加上 .off() 解除舊綁定,防止「幽靈疊加點擊」!
// 否則您每點一次,它會因為 renderItemMenu 重新綁定,導致一次加好幾個名字甚至當掉
$("#canselectItem").off("click", ".itemAppend").on("click", ".itemAppend", function (e) { $("#canselectItem").off("click", ".itemAppend").on("click", ".itemAppend", function (e) {
e.preventDefault(); e.preventDefault();
self.modifyDataAndRerender("add", $(this).siblings(".unselect").text()); let name = $(this).siblings(".unselect").text();
let fam = self.familyMembers.find(f => f.fam_name === name);
// 🌟 從親友名單帶入時,組裝成完整物件
let obj = {
IsShuWen: false, deceased: fam ? (fam.deceased === true || fam.deceased === "True") : false,
fam_gender: "", fam_name: name, fam_file: "", nospace: true, num: fam ? fam.num : 0, option_break: false
};
self.modifyDataAndRerender("add", obj);
}); });
$("#selectedItem").off("click", ".itemRemove").on("click", ".itemRemove", function (e) { $("#selectedItem").off("click", ".itemRemove").on("click", ".itemRemove", function (e) {
e.preventDefault(); e.preventDefault(); self.modifyDataAndRerender("remove", $(this).data("idx"));
self.modifyDataAndRerender("remove", $(this).closest("li").find(".selected").text());
}); });
$("#selectedItem").off("click", ".itemUp").on("click", ".itemUp", function (e) { $("#selectedItem").off("click", ".itemUp").on("click", ".itemUp", function (e) {
e.preventDefault(); e.preventDefault(); self.modifyDataAndRerender("up", $(this).data("idx"));
self.modifyDataAndRerender("up", $(this).data("idx"));
}); });
$("#selectedItem").off("click", ".itemDown").on("click", ".itemDown", function (e) { $("#selectedItem").off("click", ".itemDown").on("click", ".itemDown", function (e) {
e.preventDefault(); e.preventDefault(); self.modifyDataAndRerender("down", $(this).data("idx"));
self.modifyDataAndRerender("down", $(this).data("idx"));
}); });
$('#btn_add_custom').off("click").on('click', function (e) { $('#btn_add_custom').off("click").on('click', function (e) {
e.preventDefault(); e.preventDefault(); let val = $('#custom_txt').val().trim();
let val = $('#custom_txt').val().trim(); if (val) {
if (val) { self.modifyDataAndRerender("add", val); $('#custom_txt').val(''); } // 🌟 手動輸入時,產生帶有 num: 0 的物件
let obj = {
IsShuWen: false, deceased: false, fam_gender: "",
fam_name: val, fam_file: "", nospace: true, num: 0, option_break: false
};
self.modifyDataAndRerender("add", obj);
$('#custom_txt').val('');
}
}); });
$('#filter_txt').off("keyup").on('keyup', () => { $('#filter_txt').off("keyup").on('keyup', () => {
@@ -809,17 +776,17 @@
// ========================================== // ==========================================
$('#btn_save').off('click').on('click', async function (e) { $('#btn_save').off('click').on('click', async function (e) {
e.preventDefault(); e.preventDefault();
//let tablet = { let tablet = {
// mid_items: designer.family_deceased_N_selected, mid_items: self.properTitle,
// left_items: designer.family_deceased_Y_selected, left_items: self.alive,
// style: designer.selectStyle.style, mid_left: self.leftProperTitle,
// mid_left: designer.family_left_title, mid_right: self.rightProperTitle,
// mid_right: designer.family_right_title, addr_items: self.address,
// addr_items: designer.family_address style: self.selectStyle,
//} }
let data = { let data = {
num: 0, name: $("#template_name_txt").val(), follower_num: VueApp.follower_id, num: 0, name: $("#template_name_txt").val(), follower_num: VueApp.follower_id,
style_id: $(".styleSelector").val(),tablet:"",shuwen:"" style_id: $(".styleSelector").val(), tablet: JSON.stringify(tablet), shuwen: ""
} }
console.log("btn_save:", data); console.log("btn_save:", data);
}); });
@@ -830,25 +797,29 @@
let target = this.selectedElement.children().first(), targetArr = null; let target = this.selectedElement.children().first(), targetArr = null;
if (target.hasClass("liveList")) targetArr = this.alive; if (target.hasClass("liveList")) targetArr = this.alive;
else if (target.hasClass("nameList")) targetArr = this.properTitle; else if (target.hasClass("nameList") || target.hasClass("rosterList") || target.hasClass("ancestor-wrapper")) targetArr = this.properTitle;
else if (target.hasClass("lefttitle")) targetArr = this.leftProperTitle; else if (target.hasClass("lefttitle")) targetArr = this.leftProperTitle;
else if (target.hasClass("righttitle")) targetArr = this.rightProperTitle; else if (target.hasClass("righttitle")) targetArr = this.rightProperTitle;
else if (target.hasClass("address")) { else if (target.hasClass("address")) {
if (action === "add") this.address = payload; else if (action === "remove") this.address = ""; if (action === "add") this.address = typeof payload === 'string' ? payload : payload.fam_name;
targetArr = this.address ? [this.address] : []; else if (action === "remove") this.address = "";
targetArr = null;
} }
if (targetArr) { if (targetArr) {
if (action === "add" && !targetArr.includes(payload)) targetArr.push(payload); if (action === "add") {
else if (action === "add" && targetArr.includes(payload)) { alert("名稱已存在!"); return; } // 🌟 檢查是否已經存在 (比對物件的 fam_name)
else if (action === "remove") { let idx = targetArr.indexOf(payload); if (idx > -1) targetArr.splice(idx, 1); } if (targetArr.some(x => x.fam_name === payload.fam_name)) { alert("名稱已存在!"); return; }
targetArr.push(payload);
}
else if (action === "remove") { targetArr.splice(payload, 1); } // 🌟 刪除改用 index
else if (action === "up" && payload > 0) [targetArr[payload - 1], targetArr[payload]] = [targetArr[payload], targetArr[payload - 1]]; else if (action === "up" && payload > 0) [targetArr[payload - 1], targetArr[payload]] = [targetArr[payload], targetArr[payload - 1]];
else if (action === "down" && payload < targetArr.length - 1) [targetArr[payload], targetArr[payload + 1]] = [targetArr[payload + 1], targetArr[payload]]; else if (action === "down" && payload < targetArr.length - 1) [targetArr[payload], targetArr[payload + 1]] = [targetArr[payload + 1], targetArr[payload]];
} }
this.renderItemMenu(target); this.renderItemMenu(target);
this.rerenderPart(); this.rerenderPart();
this.renderEditorRight(); if (this.renderEditorRight) this.renderEditorRight();
}, },
rerenderPart() { rerenderPart() {
@@ -873,15 +844,20 @@
if (!d) return; if (!d) return;
this.selectedElement.empty(); this.selectedElement.empty();
let html = ""; let html = "";
// 🌟 重新導向對應的排版引擎
if (target.hasClass("nameList")) html = this.buildNameList(this.properTitle, d); // 🌟 在傳入排版引擎前,統一 map 成字串陣列
else if (target.hasClass("rosterList")) html = this.buildRosterList(this.properTitle, d); let pTitleNames = this.properTitle.map(x => typeof x === 'string' ? x : x.fam_name);
else if (target.hasClass("ancestor-wrapper")) html = this.buildCombinedList(this.properTitle, d); let aliveNames = this.alive.map(x => typeof x === 'string' ? x : x.fam_name);
else if (target.hasClass("liveList")) html = this.buildLiveList(this.alive, d); let leftNames = this.leftProperTitle.map(x => typeof x === 'string' ? x : x.fam_name);
else if (target.hasClass("lefttitle")) html = this.buildNormalWithSpace(this.leftProperTitle, d, 'lefttitle'); let rightNames = this.rightProperTitle.map(x => typeof x === 'string' ? x : x.fam_name);
else if (target.hasClass("righttitle")) html = this.buildNormalWithSpace(this.rightProperTitle, d, 'righttitle');
if (target.hasClass("nameList")) html = this.buildNameList(pTitleNames, d);
else if (target.hasClass("rosterList")) html = this.buildRosterList(pTitleNames, d);
else if (target.hasClass("ancestor-wrapper")) html = this.buildCombinedList(pTitleNames, d);
else if (target.hasClass("liveList")) html = this.buildLiveList(aliveNames, d);
else if (target.hasClass("lefttitle")) html = this.buildNormalWithSpace(leftNames, d, 'lefttitle');
else if (target.hasClass("righttitle")) html = this.buildNormalWithSpace(rightNames, d, 'righttitle');
else if (target.hasClass("address")) html = `<div class='address' style='width:${d.width}px; height:${d.height}px; font-size:${d.fontSize}px; font-family:${d.fontFamily};'>${this.address}</div>`; else if (target.hasClass("address")) html = `<div class='address' style='width:${d.width}px; height:${d.height}px; font-size:${d.fontSize}px; font-family:${d.fontFamily};'>${this.address}</div>`;
this.selectedElement.append(html); this.selectedElement.append(html);
@@ -981,33 +957,21 @@
renderEditorRight() { renderEditorRight() {
let $editorRight = $('#editor-right'); let $editorRight = $('#editor-right');
$editorRight.empty(); $editorRight.empty();
// 1. 設定為直書模式,拔除 flex,恢復自然的區塊(Block)換行特性
$editorRight.css({ $editorRight.css({
"writing-mode": "vertical-rl", "writing-mode": "vertical-rl", "text-orientation": "mixed", "padding": "20px", "display": "block"
"text-orientation": "mixed",
"padding": "20px",
"display": "block" // 🌟 關鍵:改用 block,讓每個子元素絕對獨佔一整行
}); });
// 2. 收集所有要同步的名單 // 🌟 同樣從物件萃取 fam_name
let syncNames = [ let syncNames = [
...this.properTitle, ...this.properTitle.map(x => x.fam_name),
...this.leftProperTitle, ...this.leftProperTitle.map(x => x.fam_name),
...this.rightProperTitle ...this.rightProperTitle.map(x => x.fam_name)
]; ];
// 3. 渲染名單
syncNames.forEach(name => { syncNames.forEach(name => {
let $div = $('<div></div>').css({ let $div = $('<div></div>').css({
"font-size": "16pt", "font-size": "16pt", "font-family": "DFKai-sb", "line-height": "1.2", "letter-spacing": "2px", "white-space": "pre-line", "margin-left": "25px"
"font-family": "DFKai-sb",
"line-height": "1.2",
"letter-spacing": "2px",
"white-space": "pre-line",
"margin-left": "25px" // 🌟 設定行距 (在直書模式中,左邊就是下一行的位置)
}).text(name); }).text(name);
$editorRight.append($div); $editorRight.append($div);
}); });
}, },