diff --git a/web/admin/follower/tablet_template.html b/web/admin/follower/tablet_template.html
index 9f83980..4e1da29 100644
--- a/web/admin/follower/tablet_template.html
+++ b/web/admin/follower/tablet_template.html
@@ -669,114 +669,81 @@
$("#canselectItem").empty();
let currentData = [], editLabel = "未定義區塊";
- // 🌟 1. 判斷是否為超薦牌位 (利用 item_type === 'B' 或是依據底圖名稱防呆)
- let isChaojian = false;
- 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 isChaojian = (this.item_type === 'B' || (typeof VueApp !== 'undefined' && VueApp.item_type === 'B') || (this.tabletItem && this.tabletItem.item_type === 'B')) ||
+ (this.allStyle.find(y => y.styleID == this.selectStyle)?.name || "").includes("超薦");
let requireDeceased = isChaojian;
- // 🌟 2. 判斷當前編輯區塊
- if (element.hasClass("liveList")) {
- editLabel = "陽上";
- currentData = this.alive;
- requireDeceased = false; // 🚨 陽上永遠只能選活者
- }
- 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] : [];
- }
+ if (element.hasClass("liveList")) { editLabel = "陽上"; currentData = this.alive; requireDeceased = false; }
+ 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);
- // 渲染已選
- currentData.forEach((x, index) => {
+ // 🌟 從物件中取出 fam_name 顯示
+ currentData.forEach((item, index) => {
+ let displayName = typeof item === 'string' ? item : item.fam_name;
$("#selectedItem").append(`
-
${x}
-
-
`);
+ ${displayName}
+
+
`);
});
- // 地址不需要出現親友選單
- 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() || "";
- this.familyMembers.forEach(f => {
- // 判斷該親友的生死狀態 (相容 boolean 與字串)
- let isDead = (f.deceased === true || f.deceased === "true" || f.deceased === "True");
- // 條件成立:生死符合要求 + 尚未加入 + 關鍵字相符
- if (isDead === requireDeceased && !currentData.includes(f.fam_name) && f.fam_name.includes(filterKeyword)) {
+ this.familyMembers.forEach(f => {
+ 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(`
-
- 卍
- ${f.fam_name}
-
-
- ${f.fam_title ? f.fam_title : ""}
-
-
- +
-
- `);
+ 卍 ${f.fam_name}
+ ${f.fam_title ? f.fam_title : ""}
+ +`);
}
});
-
this.bindListEvents();
},
bindListEvents() {
let self = this;
- // 🌟 修正1:加上 .off() 解除舊綁定,防止「幽靈疊加點擊」!
- // 否則您每點一次,它會因為 renderItemMenu 重新綁定,導致一次加好幾個名字甚至當掉
$("#canselectItem").off("click", ".itemAppend").on("click", ".itemAppend", function (e) {
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) {
- e.preventDefault();
- self.modifyDataAndRerender("remove", $(this).closest("li").find(".selected").text());
+ e.preventDefault(); self.modifyDataAndRerender("remove", $(this).data("idx"));
});
-
$("#selectedItem").off("click", ".itemUp").on("click", ".itemUp", function (e) {
- e.preventDefault();
- self.modifyDataAndRerender("up", $(this).data("idx"));
+ e.preventDefault(); self.modifyDataAndRerender("up", $(this).data("idx"));
});
-
$("#selectedItem").off("click", ".itemDown").on("click", ".itemDown", function (e) {
- e.preventDefault();
- self.modifyDataAndRerender("down", $(this).data("idx"));
+ e.preventDefault(); self.modifyDataAndRerender("down", $(this).data("idx"));
});
$('#btn_add_custom').off("click").on('click', function (e) {
- e.preventDefault();
- let val = $('#custom_txt').val().trim();
- if (val) { self.modifyDataAndRerender("add", val); $('#custom_txt').val(''); }
+ e.preventDefault(); let val = $('#custom_txt').val().trim();
+ if (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', () => {
@@ -809,17 +776,17 @@
// ==========================================
$('#btn_save').off('click').on('click', async function (e) {
e.preventDefault();
- //let tablet = {
- // mid_items: designer.family_deceased_N_selected,
- // left_items: designer.family_deceased_Y_selected,
- // style: designer.selectStyle.style,
- // mid_left: designer.family_left_title,
- // mid_right: designer.family_right_title,
- // addr_items: designer.family_address
- //}
+ let tablet = {
+ mid_items: self.properTitle,
+ left_items: self.alive,
+ mid_left: self.leftProperTitle,
+ mid_right: self.rightProperTitle,
+ addr_items: self.address,
+ style: self.selectStyle,
+ }
let data = {
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);
});
@@ -830,25 +797,29 @@
let target = this.selectedElement.children().first(), targetArr = null;
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("righttitle")) targetArr = this.rightProperTitle;
else if (target.hasClass("address")) {
- if (action === "add") this.address = payload; else if (action === "remove") this.address = "";
- targetArr = this.address ? [this.address] : [];
+ if (action === "add") this.address = typeof payload === 'string' ? payload : payload.fam_name;
+ else if (action === "remove") this.address = "";
+ targetArr = null;
}
if (targetArr) {
- if (action === "add" && !targetArr.includes(payload)) targetArr.push(payload);
- else if (action === "add" && targetArr.includes(payload)) { alert("名稱已存在!"); return; }
- else if (action === "remove") { let idx = targetArr.indexOf(payload); if (idx > -1) targetArr.splice(idx, 1); }
+ if (action === "add") {
+ // 🌟 檢查是否已經存在 (比對物件的 fam_name)
+ 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 === "down" && payload < targetArr.length - 1) [targetArr[payload], targetArr[payload + 1]] = [targetArr[payload + 1], targetArr[payload]];
}
this.renderItemMenu(target);
this.rerenderPart();
- this.renderEditorRight();
+ if (this.renderEditorRight) this.renderEditorRight();
},
rerenderPart() {
@@ -873,15 +844,20 @@
if (!d) return;
this.selectedElement.empty();
-
let html = "";
- // 🌟 重新導向對應的排版引擎
- if (target.hasClass("nameList")) html = this.buildNameList(this.properTitle, d);
- else if (target.hasClass("rosterList")) html = this.buildRosterList(this.properTitle, d);
- else if (target.hasClass("ancestor-wrapper")) html = this.buildCombinedList(this.properTitle, d);
- else if (target.hasClass("liveList")) html = this.buildLiveList(this.alive, d);
- else if (target.hasClass("lefttitle")) html = this.buildNormalWithSpace(this.leftProperTitle, d, 'lefttitle');
- else if (target.hasClass("righttitle")) html = this.buildNormalWithSpace(this.rightProperTitle, d, 'righttitle');
+
+ // 🌟 在傳入排版引擎前,統一 map 成字串陣列
+ let pTitleNames = this.properTitle.map(x => typeof x === 'string' ? x : x.fam_name);
+ let aliveNames = this.alive.map(x => typeof x === 'string' ? x : x.fam_name);
+ let leftNames = this.leftProperTitle.map(x => typeof x === 'string' ? x : x.fam_name);
+ let rightNames = this.rightProperTitle.map(x => typeof x === 'string' ? x : x.fam_name);
+
+ 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 = `${this.address}
`;
this.selectedElement.append(html);
@@ -981,33 +957,21 @@
renderEditorRight() {
let $editorRight = $('#editor-right');
$editorRight.empty();
-
- // 1. 設定為直書模式,拔除 flex,恢復自然的區塊(Block)換行特性
$editorRight.css({
- "writing-mode": "vertical-rl",
- "text-orientation": "mixed",
- "padding": "20px",
- "display": "block" // 🌟 關鍵:改用 block,讓每個子元素絕對獨佔一整行
+ "writing-mode": "vertical-rl", "text-orientation": "mixed", "padding": "20px", "display": "block"
});
- // 2. 收集所有要同步的名單
+ // 🌟 同樣從物件萃取 fam_name
let syncNames = [
- ...this.properTitle,
- ...this.leftProperTitle,
- ...this.rightProperTitle
+ ...this.properTitle.map(x => x.fam_name),
+ ...this.leftProperTitle.map(x => x.fam_name),
+ ...this.rightProperTitle.map(x => x.fam_name)
];
- // 3. 渲染名單
syncNames.forEach(name => {
let $div = $('').css({
- "font-size": "16pt",
- "font-family": "DFKai-sb",
- "line-height": "1.2",
- "letter-spacing": "2px",
- "white-space": "pre-line",
- "margin-left": "25px" // 🌟 設定行距 (在直書模式中,左邊就是下一行的位置)
+ "font-size": "16pt", "font-family": "DFKai-sb", "line-height": "1.2", "letter-spacing": "2px", "white-space": "pre-line", "margin-left": "25px"
}).text(name);
-
$editorRight.append($div);
});
},