migrate to new git

This commit is contained in:
2025-08-29 01:27:25 +08:00
parent 946eb9961e
commit af2c152ef6
8623 changed files with 1000453 additions and 1 deletions

View File

@@ -0,0 +1,602 @@
<!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>
</div>
<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:none;">
<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>