Files
17168ERP/web/admin/print/tablet_edit/editor.html
yiming e6c6b1f43f 更正問題:
入帳必填檢查
修正牌位排版HTML
2025-09-05 08:14:03 +08:00

605 lines
31 KiB
HTML
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.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="../../../js/vuetify.css" rel="stylesheet" />
<link href="../../../js/mdi-font/css/materialdesignicons.min.css" rel="stylesheet" />
<script src="../../../js/vue.min.js"></script>
<script src="../../../js/vuetify.min.js"></script>
<script src="../../../js/axios.min.js"></script>
<style>
html {
overflow: hidden;
}
.scrollable-list {
max-height: 250px;
height: 220px;
overflow-y: auto;
overflow-x: hidden;
}
.scrollable-list .v-list-item__content {
padding: 4px 0px;
}
.scrollable-list .v-list-item {
min-height: 30px;
padding: 0 8px;
}
.scrollable-list .v-list-item__action {
min-width: 0 !important;
width: auto !important;
margin-right: 0 !important;
}
.scrollable-list .v-btn--icon.v-size--default {
height: 24px;
width: 24px;
}
#app .v-card__subtitle,
#app .v-card__text,
#app .v-card__title {
padding: 12px 16px 0 16px;
}
#app .v-list-item.hover-item .v-list-item__subtitle {
/*display: none !important;*/
display: flex !important;
}
#app .v-list-item.hover-item:hover .v-list-item__subtitle {
display: flex !important;
}
.badge-deceased {
background-color: #ffc904;
color: #300a0a;
padding: 2px 4px;
border-radius: 20px;
font-weight: bold;
font-size: 10px;
display: inline-block;
position: relative;
top: -2px;
}
.badge-zero {
background-color: #CCC;
color: #FFF;
padding: 2px 4px;
border-radius: 20px;
font-weight: bold;
font-size: 10px;
display: inline-block;
position: relative;
top: -2px;
}
.equal-card {
min-height: 260px;
}
.checkbox-narrow {
min-width: 32px;
width: 32px;
padding: 0;
margin-right: 4px;
}
</style>
<link rel="stylesheet" href="print.css">
</head>
<body>
<div id="app">
<v-app>
<v-container>
<v-row>
<v-col cols="4" md="4">
<v-card class="pa-2" outlined tile>
<div class="docs editor">
<div class="page border" data-body-class="tblt-l a3">
<div class="content">
<div class="bg"><img alt="Alternate Text" :src="'../' + item_type_image"></div>
<div class="text">
<div class="top_text_1"></div>
<div class="top_text_2">{{tabletItem.print_id}}</div>
<div class="top_text_3"></div>
<div class="right_text text-block fit-text vertical text-start border"
style="--lines:0;--line_len:5;"></div>
<div class="mid_text text-block fit-text vertical border"
:style="mid_text_style" v-html="join_mid_text"></div>
<div class="mid_text_2 text-block fit-text vertical border"
style="--lines:0;--line_len:5;"></div>
<div class="left_text text-block fit-text vertical text-start border"
:style="left_text_style" v-html="join_left_text"></div>
<div class="txt_up vertical" v-if="item_type == 'B'">陽上</div>
<div class="txt_down vertical" v-if="item_type == 'B'">拜薦</div>
</div>
</div>
</div>
</div>
</v-card>
<div class="mt-2">
<v-btn color="primary" @click="saveData">儲存牌位</v-btn>
</div>
</v-col>
<v-col cols="4" md="4" id="type_edit_B" v-if="item_type==='B'" class="d-flex flex-column">
<v-card elevation="2" class="mb-2 equal-card">
<v-checkbox v-model="isAllSelected"
@change="toggleSelectAll"
color="primary"
hide-details
class="checkbox-narrow d-inline-flex"></v-checkbox>
<v-card-subtitle class="d-inline-flex ">疏文代表</v-card-subtitle>
<v-card-subtitle class="d-inline-flex ml-2">超渡-已選</v-card-subtitle>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="(member, index) in family_deceased_Y_selected" :key="member.num" class="hover-item">
<v-list-item-action>
<v-checkbox v-model="member.IsShuWen"
color="primary"
class="checkbox-narrow d-inline-flex align-center" />
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
<span class="badge-zero" v-if="member.num==0">0</span>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
<v-list-item-subtitle class="d-flex justify-end">
<v-btn icon @click="moveUp(member, 'Y', index)" :disabled="index === 0">
<v-icon color="grey lighten-1">mdi-arrow-up</v-icon>
</v-btn>
<v-btn icon @click="moveDown(member, 'Y', index)" :disabled="index === family_deceased_Y_selected.length - 1">
<v-icon color="grey lighten-1">mdi-arrow-down</v-icon>
</v-btn>
<v-btn icon @click="removeFromSelected(member, 'Y')">
<v-icon color="grey lighten-1">mdi-minus</v-icon>
</v-btn>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action class="align-self-start">
<v-btn icon @click="breakAfter(member, 'Y')">
<v-icon :color="member.option_break ? 'blue' : 'grey lighten-1'">
mdi-subdirectory-arrow-left
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
<v-card elevation="2" class="equal-card">
<v-card-subtitle>超渡-可選</v-card-subtitle>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="member in family_deceased_Y_unselected" :key="member.fam_name">
<v-list-item-content>
<v-list-item-title>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="addToSelected(member, 'Y')">
<v-icon color="grey lighten-1">mdi-plus</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
</v-col>
<v-col cols="4" md="4" id="type_edit_AB" class="d-flex flex-column">
<v-card elevation="2" class="mb-2 equal-card">
<v-checkbox v-model="isAllSelected"
@change="toggleSelectAll"
color="primary"
hide-details
class="checkbox-narrow d-inline-flex align-center" v-if="item_type==='A'"></v-checkbox>
<v-card-subtitle class="d-inline-flex align-center" v-if="item_type==='A'">疏文代表</v-card-subtitle>
<v-card-subtitle class="d-inline-flex align-center ml-2">陽上/祈福-已選</v-card-subtitle>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="(member, index) in family_deceased_N_selected" :key="member.num" class="hover-item">
<v-list-item-action v-if="item_type==='A'">
<v-checkbox v-model="member.IsShuWen"
color="primary"
class="checkbox-narrow d-inline-flex align-center" />
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
<span class="badge-zero" v-if="member.num==0">0</span>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
<v-list-item-subtitle class="d-flex justify-end">
<v-btn icon @click="moveUp(member, 'N', index)" :disabled="index === 0">
<v-icon color="grey lighten-1">mdi-arrow-up</v-icon>
</v-btn>
<v-btn icon @click="moveDown(member, 'N', index)" :disabled="index === family_deceased_N_selected.length - 1">
<v-icon color="grey lighten-1">mdi-arrow-down</v-icon>
</v-btn>
<v-btn icon @click="removeFromSelected(member, 'N')">
<v-icon color="grey lighten-1">mdi-minus</v-icon>
</v-btn>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action class="align-self-start">
<v-btn icon @click="breakAfter(member, 'N')">
<v-icon :color="member.option_break ? 'blue' : 'grey lighten-1'">
mdi-subdirectory-arrow-left
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
<v-card elevation="2" class="equal-card">
<v-card-subtitle>陽上/祈福-可選</v-card-subtitle>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="member in family_deceased_N_unselected" :key="member.fam_name">
<v-list-item-content>
<v-list-item-title>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="addToSelected(member, 'N')">
<v-icon color="grey lighten-1">mdi-plus</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
</v-col>
</v-row>
</v-container>
<div style="display:block;">
<textarea id="desc_iframe" style="width: 900px; height: 100px;">{{tabletItem}}</textarea>
</div>
</v-app>
</div>
<script>
var VueApp = new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
isAllSelected: false,
dialog: false,
familyMembers: [], // 親友名單
tabletItem: {}, // 傳入的資料(信眾/牌位資訊)
item: {},
family_deceased_Y_selected: [], // 超渡/超薦/超冤名單
family_deceased_N_selected: [] // 消災/陽上名單
};
},
watch: {
family_deceased_N_selected: {
handler(newValue) {
if (this.item_type === 'A') {
if (Array.isArray(newValue) && newValue.length > 0) {
this.isAllSelected = newValue.every(member => member.IsShuWen === true);
}
}
},
deep: true
},
family_deceased_Y_selected: {
handler(newValue) {
if (this.item_type === 'B') {
if (Array.isArray(newValue) && newValue.length > 0) {
this.isAllSelected = newValue.every(member => member.IsShuWen === true);
}
}
},
deep: true
}
},
computed: {
family_deceased_Y_unselected() {
return this.familyMembers.filter(member =>
member.deceased === true &&
!this.family_deceased_Y_selected.some(selected => selected.num === member.num));
},
family_deceased_N_unselected() {
return this.familyMembers.filter(member =>
member.deceased === false &&
!this.family_deceased_N_selected.some(selected => selected.num === member.num));
},
item_type() {
return this.tabletItem?.actitem_num_selected?.text?.includes('超') ? 'B' : 'A';
// A:消災, 陽上.....
// B:超渡, 超薦.....
},
item_type_image() {
if (this.item_type === 'B') {
return 'tablet-1.svg';
} else {
return 'tablet-2.svg';
}
},
join_mid_text() {
const target = this.item_type === 'B'
? this.family_deceased_Y_selected
: this.family_deceased_N_selected;
return this.join_text(target);
},
join_left_text() {
let target = '';
if (this.item_type === 'B') {
target = this.join_text(this.family_deceased_N_selected);
}
return target;
},
mid_text_style() {
const text = this.join_mid_text; // Remove function call since join_mid_text is a computed property
return this.calculateTextStyle(text);
},
left_text_style() {
if (this.item_type !== 'B') return '--lines:1;--line_len:5';
return this.calculateTextStyle(this.join_left_text);
}
},
mounted() {
// 監聽來自父頁面的消息
window.addEventListener('message', (event) => {
this.isAllSelected = false;
console.log('editor.html - received message event');
console.log('editor.html - event origin:', event.origin);
console.log('editor.html - parent origin:', window.parent.location.origin);
if (event.origin === window.parent.location.origin) {
console.log('editor.html - origin check passed');
console.log('editor.html - received data:', event.data);
const receivedData = event.data;
this.family_deceased_Y_selected = [];
this.family_deceased_N_selected = [];
if (receivedData.tabletItem) {
console.log('editor.html - updating tabletItem:', receivedData.tabletItem);
this.tabletItem = receivedData.tabletItem;
if (receivedData.familyMembers) {
this.familyMembers = receivedData.familyMembers; // 更新 familyMembers
console.log("app mounted, window message: ", this.familyMembers, receivedData);
}
if (receivedData.tabletItem) {
this.tabletItem = receivedData.tabletItem;
}
// 處理 f_num_tablet 資料
if (this.tabletItem.f_num_tablet) {
try {
const data = JSON.parse(this.tabletItem.f_num_tablet);
if (this.item_type === 'B') {
// B類型超渡、超薦等
this.family_deceased_Y_selected = data.mid_items || [];
this.family_deceased_N_selected = data.left_items || [];
this.family_deceased_Y_selected.forEach(item => {
if (item.IsShuWen === undefined) {
Vue.set(item, 'IsShuWen', false);
}
});
if (this.family_deceased_Y_selected.length > 0) {
this.isAllSelected = this.family_deceased_Y_selected.every(member => member.IsShuWen === true);
} else {
this.isAllSelected = false;
}
} else {
// A類型消災、陽上等
this.family_deceased_Y_selected = [];
this.family_deceased_N_selected = data.mid_items || [];
this.family_deceased_N_selected.forEach(item => {
if (item.IsShuWen === undefined) {
Vue.set(item, 'IsShuWen', false);
}
});
if (this.family_deceased_Y_selected.length > 0) {
this.isAllSelected = this.family_deceased_N_selected.every(member => member.IsShuWen === true);
} else {
this.isAllSelected = false;
}
console.log(this.family_deceased_N_selected)
}
} catch (e) {
console.error('解析牌位資料時發生錯誤:', e);
}
}
}
}
});
},
methods: {
toggleSelectAll(checked) {
this.isAllSelected = checked
if (this.item_type === 'B') {
this.family_deceased_Y_selected.forEach(member => {
member.IsShuWen = checked;
});
}
else if (this.item_type === 'A') {
this.family_deceased_N_selected.forEach(member => {
member.IsShuWen = checked;
});
}
console.log(checked)
console.log(this.family_deceased_N_selected)
console.log(this.family_deceased_Y_selected)
},
addToSelected(member, type) {
const selectedMember = {
num: member.num,
fam_name: member.fam_name,
fam_gender: member.fam_gender,
deceased: member.deceased,
fam_title: member.fam_title, // 新增,讓上方顯示稱謂 tag
option_break: false, // 默認為 false根據需要可以更改
IsShuWen: this.isAllSelected //是否加入疏文名單,默認false
};
console.log(this.isAllSelected)
if (type === 'Y') {
this.family_deceased_Y_selected.push(selectedMember);
console.log(this.family_deceased_Y_selected)
} else if (type === 'N') {
this.family_deceased_N_selected.push(selectedMember);
console.log(this.family_deceased_N_selected)
}
},
removeFromSelected(member, type) {
if (type === 'Y') {
this.family_deceased_Y_selected.forEach(m => {
if (m.num === member.num) {
Vue.delete(m, 'IsShuWen');
}
});
this.family_deceased_Y_selected = this.family_deceased_Y_selected.filter(m => m.num !== member.num);
} else if (type === 'N') {
this.family_deceased_N_selected.forEach(m => {
if (m.num === member.num) {
Vue.delete(m, 'IsShuWen');
}
});
this.family_deceased_N_selected = this.family_deceased_N_selected.filter(m => m.num !== member.num);
}
},
moveUp(member, type, index) {
if (index > 0) {
const array = type === 'Y' ? this.family_deceased_Y_selected : this.family_deceased_N_selected;
const temp = array[index - 1];
this.$set(array, index - 1, member);
this.$set(array, index, temp);
}
},
moveDown(member, type, index) {
if (index < (type === 'Y' ? this.family_deceased_Y_selected : this.family_deceased_N_selected).length - 1) {
const array = type === 'Y' ? this.family_deceased_Y_selected : this.family_deceased_N_selected;
const temp = array[index + 1];
this.$set(array, index + 1, member);
this.$set(array, index, temp);
}
},
breakAfter(member, type) {
console.log("breakAfter", member, type);
member.option_break = !member.option_break;
},
join_text(target) {
// console.log("join_text", target);
// join each item by ' '
// and for each item, if true for "option_break", then add "<br>" in the item text
let result = '';
target.forEach((member, index) => {
result += member.fam_name;
// Add break if option_break is true and not the last item
if (member.option_break && index < target.length - 1) {
result += '<br>';
} else if (index < target.length - 1) {
// Add space between names if not the last item and no break
result += ' ';
}
});
result = result.replace('|', '<br>');
return result;
},
calculateTextStyle(text) {
if (!text) return '--lines:1;--line_len:5';
const lines = text.split('<br>');
const line_len = Math.max(...lines.map(line => {
return Array.from(line).reduce((acc, char) => {
// Full width (Chinese) characters
if (char.match(/[\u4e00-\u9fa5]/)) {
return acc + 1;
}
// Half width (English, numbers, etc.)
return acc + 0.5;
}, 0);
}));
return `--lines:${lines.length};--line_len:${Math.ceil(line_len)}`;
},
saveData() {
// 其它資料欄位, 不應在這裡修改
// 應該在進來的時候, 就已經修改(insert)好了
let tablet_data = {};
if (this.item_type === 'B') {// B:超渡, 超薦.....
tablet_data = {
mid_items: this.family_deceased_Y_selected,
left_items: this.family_deceased_N_selected
}
}
else {// A:消災, 陽上.....
tablet_data = {
mid_items: this.family_deceased_N_selected,
left_items: null
}
}
console.log(tablet_data)
const ret = {
source: 'editor.btn.click',
data: {
tabletItem: this.tabletItem,
tablet_data: tablet_data
}
};
console.log("儲存牌位資料", ret);
window.parent.postMessage(ret, '/');
}
}
});
</script>
<script>
const desc_iframe = document.getElementById('desc_iframe');
const btn = document.getElementById('btn');
//window.addEventListener('message', (event) => {
// if (event.source === window.parent) {
// let data = event.data;
// if (data.source === 'order.btn.click') {
// console.log('editor message', event.source, window.parent);
// app.item = data;
// console.log(app);
// desc_iframe.value = JSON.stringify(data);
// }
// }
//});
/*
btn.addEventListener('click', () => {
const ret = {
source: 'editor.btn.click',
desc: desc_iframe.value,
}
debugger;
console.log("btn click", ret);
window.parent.postMessage(ret, '/');
});
*/
</script>
</body>
</html>