569 lines
25 KiB
Plaintext
569 lines
25 KiB
Plaintext
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletposition_index" %>
|
|
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
|
</asp:Content>
|
|
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
|
<nav class="mb-2 ps-3">
|
|
<button class="btn btn-secondary me-2" @click="expandAll" type="button">
|
|
<i class="mdi mdi-arrow-expand-all"></i> 全部展開
|
|
</button>
|
|
<button class="btn btn-secondary" @click="collapseAll" type="button">
|
|
<i class="mdi mdi-arrow-collapse-all"></i> 全部收起
|
|
</button>
|
|
</nav>
|
|
</asp:Content>
|
|
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-sm-4 col-lg-2">
|
|
<div class="card shadow-sm my-2">
|
|
<div class="card-header">神主牌區域列表</div>
|
|
<div class="card-body">
|
|
<ul class="tree">
|
|
<li v-for="area in ancestral_tablet_areas" :key="area.AreaId">
|
|
<region-item
|
|
:item="area"
|
|
:selected-id="currentSelectAreaId"
|
|
@select-area="selectAreaMethod"
|
|
:expand-all="expandAllFlag"
|
|
:collapse-all="collapseAllFlag"
|
|
@clear-expand-all="expandAllFlag = false"
|
|
@clear-collapse-all="collapseAllFlag = false"
|
|
/>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-4 col-lg-10" v-if="currentSelectArea">
|
|
<div class="card shadow-sm my-2" style="position: sticky; top: 20px; display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;">
|
|
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;background-color: #ffc107;">
|
|
<div>
|
|
{{currentSelectArea.areaName + ' - ' + '神主牌位置'}}
|
|
</div>
|
|
</div>
|
|
<div class="card-body" style="flex: 1 1 auto; min-height: 0; overflow: auto;">
|
|
<div class="grid-container">
|
|
<div
|
|
v-for="pos in positions"
|
|
:key="pos.positionCode"
|
|
class="grid-item"
|
|
:class="'status-' + pos.statusCode"
|
|
:style="{ gridRow: pos.rowNo, gridColumn: pos.columnNo }"
|
|
>
|
|
<div class="position-name">{{ pos.positionName }}</div>
|
|
<div class="position-content">
|
|
<span v-if="pos.statusCode == 'maintenance'">維護中</span>
|
|
<v-btn v-else-if="!pos.ancestralTabletRegistrant" @click="showCreatePWMethod(pos)">登記</v-btn>
|
|
<!-- 已預訂 -->
|
|
<div v-else>
|
|
<div>登記人:{{ pos.ancestralTabletRegistrant?.name }}</div>
|
|
<div>登記日期:{{ pos.ancestralTabletRegistrant?.registerDate|timeString('YYYY/MM/DD') }}</div>
|
|
<v-btn small color="btn-primary" @click="showEditPWMethod(pos)">
|
|
詳細資訊
|
|
</v-btn>
|
|
|
|
</>
|
|
</div>
|
|
|
|
<!-- 已使用 -->
|
|
<div v-else-if="pos.statusCode === 'used'">
|
|
<div>已使用</div>
|
|
<div v-if="pos.usedBy">使用人:{{ pos.usedBy }}</div>
|
|
<div v-if="pos.usedDate">使用日期:{{ pos.usedDate|timeString('YYYY/MM/DD') }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 登記資料彈出視窗 -->
|
|
<div>
|
|
<v-dialog v-model="showCreatePWFlag" max-width="800">
|
|
<v-card>
|
|
<v-card-title class="headline">登記資料({{'位置: ' + selectedPos?.positionName}})</v-card-title>
|
|
<v-card-text>
|
|
<!-- 登記人資料 -->
|
|
<hr />
|
|
<h5>登記人資料</h5>
|
|
<label>姓名:
|
|
<input class="form-control" type="text" v-model="form.createRegister.name" />
|
|
</label><br />
|
|
<label>電話:
|
|
<input class="form-control" type="text" v-model="form.createRegister.phone" />
|
|
</label><br />
|
|
<label>住址:
|
|
<input class="form-control" type="text" v-model="form.createRegister.address" />
|
|
</label><br />
|
|
<label>費用:
|
|
<input class="form-control" v-model="form.createRegister.price" />
|
|
</label><br />
|
|
<label>登記時間:
|
|
<input class="form-control" type="date" v-model="form.createRegister.registerDate" />
|
|
</label><br />
|
|
<label>開始時間:
|
|
<input class="form-control" type="date" v-model="form.createRegister.startDate" />
|
|
</label><br />
|
|
<label>結束時間:
|
|
<input class="form-control" type="date" v-model="form.createRegister.endDate" />
|
|
</label><br />
|
|
<label>長期有效:
|
|
<input type="checkbox" v-model="form.createRegister.isLongTerm" />
|
|
</label><br />
|
|
<label>是否啟用:
|
|
<input type="checkbox" v-model="form.createRegister.isActive" />
|
|
</label><br />
|
|
<div class="mt-2 mb-4">
|
|
<button
|
|
v-if="!form.createRegister.registrantCode"
|
|
class="btn btn-primary"
|
|
type="button"
|
|
@click="saveRegistrantMethod">
|
|
保存登記人
|
|
</button>
|
|
<button
|
|
v-else
|
|
class="btn btn-primary"
|
|
type="button"
|
|
@click="updateRegistrantMethod">
|
|
送出修改
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 牌位資料 -->
|
|
<hr />
|
|
<h5>牌位資料</h5>
|
|
<label>牌位標題:
|
|
<input class="form-control" type="text" v-model="form.createPositionRecord.npTitle" />
|
|
</label><br />
|
|
<label>立牌時間:
|
|
<input class="form-control" type="date" v-model="form.createPositionRecord.npStandDate" />
|
|
</label><br />
|
|
<label>陽上:
|
|
<input class="form-control" type="text" v-model="form.createPositionRecord.npYangShang" />
|
|
</label><br />
|
|
<label>內牌內容:</label>
|
|
<textarea
|
|
class="form-control"
|
|
rows="4"
|
|
v-model="form.createPositionRecord.wpContent"
|
|
style="width: 100%; box-sizing: border-box;"
|
|
></textarea><br />
|
|
<div class="mt-2 mb-2">
|
|
<button v-if="form.createPositionRecord.recordId == null" class="btn btn-primary" type="button" @click="saveCreatePositionRecordMethod">保存牌位</button>
|
|
<button v-else type="button" class="btn btn-primary" @click="updateCreatePositionRecordMethod">
|
|
送出修改
|
|
</button>
|
|
</div>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer></v-spacer>
|
|
<button class="btn btn-secondary" type="button" @click="closePWDialogMethod">關閉</button>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</div>
|
|
|
|
</asp:Content>
|
|
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
|
</asp:Content>
|
|
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
|
<script>
|
|
Vue.component('region-item', {
|
|
props: ['item', 'selectedId', 'expandAll', 'collapseAll'],
|
|
data() {
|
|
return {
|
|
expanded: false, // 預設全部收起
|
|
}
|
|
},
|
|
watch: {
|
|
expandAll(newVal) {
|
|
if (newVal) {
|
|
this.expanded = true;
|
|
// 執行完後發事件通知父組件清除標誌
|
|
this.$nextTick(() => this.$emit('clear-expand-all'));
|
|
}
|
|
},
|
|
collapseAll(newVal) {
|
|
if (newVal) {
|
|
this.expanded = false;
|
|
this.$nextTick(() => this.$emit('clear-collapse-all'));
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
hasChildren() {
|
|
return this.item.children && this.item.children.length > 0;
|
|
},
|
|
icon() {
|
|
// 無論有無子節點,皆可點擊展開/收起
|
|
return this.expanded ? '▼' : '▶';
|
|
},
|
|
isSelected() {
|
|
return this.item.areaId === this.selectedId;
|
|
}
|
|
},
|
|
methods: {
|
|
toggle() {
|
|
this.expanded = !this.expanded;
|
|
},
|
|
select() {
|
|
this.$emit('select-area', this.item);
|
|
},
|
|
},
|
|
template: `
|
|
<div>
|
|
<span class="toggle-icon" @click="toggle">{{ icon }}</span>
|
|
<span @click="select"
|
|
class="region-item-label"
|
|
:class="{ 'selected': isSelected }">
|
|
{{ item.areaName }}
|
|
</span>
|
|
|
|
<!-- 子區域列表 -->
|
|
<ul v-if="hasChildren && expanded">
|
|
<li v-for="child in item.children" :key="child.areaId">
|
|
<region-item
|
|
:item="child"
|
|
:selected-id="selectedId"
|
|
:expand-all="expandAll"
|
|
:collapse-all="collapseAll"
|
|
@select-area="$emit('select-area', $event)"
|
|
@clear-expand-all="$emit('clear-expand-all')"
|
|
@clear-collapse-all="$emit('clear-collapse-all')"
|
|
/>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
`
|
|
});
|
|
Vue.filter('timeString', function (value, myFormat) {
|
|
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
|
|
});
|
|
new Vue({
|
|
el: '#app',
|
|
vuetify: new Vuetify(vuetify_options),
|
|
data() {
|
|
return {
|
|
expandAllFlag: false, // 控制全部展開
|
|
collapseAllFlag: false, // 控制全部收起
|
|
ancestral_tablet_areas: [], //神主牌區域列表
|
|
currentSelectArea: null,
|
|
currentSelectAreaId: null,
|
|
statusList: [],
|
|
//--------------------------------神主牌位置變數
|
|
positions: [],
|
|
selectedPos: null, //點擊登記的的pos
|
|
showCreatePWFlag: false, //控制是否打開登記神主牌位資料彈出視窗
|
|
form: {
|
|
createRegister: {
|
|
//新增登記人form
|
|
registrantCode: null, // 登記編號
|
|
positionId: null,
|
|
name: null,
|
|
phone: null,
|
|
address: null,
|
|
registerDate: null,
|
|
price: null,
|
|
startDate: null,
|
|
endDate: null,
|
|
isLongTerm: false,
|
|
isActive: true,
|
|
|
|
|
|
},
|
|
createPositionRecord: {
|
|
//新增牌位登記form
|
|
recordId: null, // 自增主鍵,前端一般不用填
|
|
registrantCode: null, // 外鍵,關聯登記人編號
|
|
npTitle: null,
|
|
npStandDate: null,
|
|
npYangShang: null,
|
|
wpContent: null,
|
|
},
|
|
},
|
|
//--------------------------------神主牌位置變數
|
|
|
|
}
|
|
},
|
|
methods: {
|
|
selectAreaMethod(area) {
|
|
this.currentSelectAreaId = area.areaId;
|
|
this.currentSelectArea = area;
|
|
this.loadTabletPositionsMethod(area.areaId);
|
|
},
|
|
getAreaListMethod() {
|
|
//獲取區域列表
|
|
axios.get(HTTP_HOST + 'api/ancestraltablet/area/getlist')
|
|
.then(res => {
|
|
this.ancestral_tablet_areas = res.data
|
|
})
|
|
},
|
|
expandAll() {
|
|
this.expandAllFlag = true;
|
|
this.collapseAllFlag = false;
|
|
},
|
|
collapseAll() {
|
|
this.collapseAllFlag = true;
|
|
this.expandAllFlag = false;
|
|
},
|
|
//--------------------------------神主牌位置相關函數
|
|
loadTabletPositionsMethod(areaId) {
|
|
axios.get(HTTP_HOST + 'api/ancestraltablet/position/getlist', {
|
|
params: {
|
|
areaId: areaId
|
|
}
|
|
})
|
|
.then(response => {
|
|
this.positions = response.data;
|
|
})
|
|
.catch(error => {
|
|
console.error('失敗:', error);
|
|
});
|
|
},
|
|
showCreatePWMethod(pos) {
|
|
//打開新增彈出視窗
|
|
this.selectedPos = pos;
|
|
this.showCreatePWFlag = true;
|
|
this.form.createRegister.positionId = pos.positionId
|
|
this.form.createRegister.price = pos.price
|
|
},
|
|
showEditPWMethod(pos) {
|
|
//打開編輯彈出視窗
|
|
this.selectedPos = pos;
|
|
const registrant = pos.ancestralTabletRegistrant;
|
|
|
|
if (registrant) {
|
|
this.form.createRegister.registrantCode = registrant.registrantCode;
|
|
this.form.createRegister.positionId = pos.positionId;
|
|
this.form.createRegister.name = registrant.name;
|
|
this.form.createRegister.phone = registrant.phone;
|
|
this.form.createRegister.address = registrant.address;
|
|
this.form.createRegister.registerDate = registrant.registerDate
|
|
? registrant.registerDate?.split('T')[0]
|
|
: '';
|
|
this.form.createRegister.price = registrant.price;
|
|
this.form.createRegister.startDate = registrant.startDate ? registrant.startDate?.split('T')[0]
|
|
: '';
|
|
this.form.createRegister.endDate = registrant.endDate ? registrant.endDate?.split('T')[0]
|
|
: '';
|
|
this.form.createRegister.isLongTerm = registrant.isLongTerm;
|
|
this.form.createRegister.isActive = registrant.isActive;
|
|
this.form.createPositionRecord.registrantCode = registrant.registrantCode;
|
|
this.showCreatePWFlag = true;
|
|
if (registrant.tabletRecord) {
|
|
this.form.createPositionRecord.recordId = registrant.tabletRecord.recordId;
|
|
this.form.createPositionRecord.registrantCode = registrant.tabletRecord.registrantCode;
|
|
this.form.createPositionRecord.npTitle = registrant.tabletRecord.npTitle;
|
|
this.form.createPositionRecord.npStandDate = registrant.tabletRecord.npStandDate ? registrant.tabletRecord.npStandDate.split('T')[0]
|
|
: '';
|
|
this.form.createPositionRecord.npYangShang = registrant.tabletRecord.npYangShang;
|
|
this.form.createPositionRecord.wpContent = registrant.tabletRecord.wpContent;
|
|
}
|
|
}
|
|
},
|
|
closePWDialogMethod(pos) {
|
|
//關閉編輯彈出視窗
|
|
this.selectedPos = null;
|
|
|
|
// 重設登記人欄位
|
|
this.form.createRegister = {
|
|
registrantCode: null,
|
|
positionId: null,
|
|
name: null,
|
|
phone: null,
|
|
address: null,
|
|
registerDate: null,
|
|
price: null,
|
|
startDate: null,
|
|
endDate: null,
|
|
isLongTerm: false,
|
|
isActive: false
|
|
};
|
|
|
|
// 清空牌位記錄
|
|
this.form.createPositionRecord = {
|
|
recordId: null,
|
|
registrantCode: null,
|
|
npTitle: null,
|
|
npStandDate: null,
|
|
npYangShang: null,
|
|
wpContent: null
|
|
};
|
|
|
|
this.showCreatePWFlag = false;
|
|
},
|
|
//--------------------------------神主牌位置相關函數
|
|
//--------------------------------登記人相關函數 start
|
|
async saveRegistrantMethod() {
|
|
try {
|
|
const response = await axios.post(HTTP_HOST + 'api/ancestraltablet/registrant/create', this.form.createRegister);
|
|
console.log('保存成功', response.data);
|
|
|
|
// 可選:提示用戶、關閉對話框、刷新數據等
|
|
this.$toast?.success('登記人保存成功'); // 取決於你是否使用 toast 插件
|
|
this.form.createRegister.registrantCode = response.data.registrantCode
|
|
this.form.createPositionRecord.registrantCode = response.data.registrantCode
|
|
this.loadTabletPositionsMethod(this.selectedPos.areaId)
|
|
alert("修改成功")
|
|
} catch (error) {
|
|
console.error('保存失敗', error);
|
|
this.$toast?.error('登記人保存失敗');
|
|
}
|
|
},
|
|
updateRegistrantMethod() {
|
|
axios.post(HTTP_HOST + 'api/ancestraltablet/registrant/update', this.form.createRegister)
|
|
.then(response => {
|
|
console.log('登記人更新成功:', response.data);
|
|
this.$toast?.success?.('登記人更新成功'); // 可選:使用 toast 彈出提示
|
|
//this.showCreatePWFlag = false; // 關閉彈出視窗
|
|
// 可選:刷新列表等
|
|
this.loadTabletPositionsMethod(this.selectedPos.areaId)
|
|
alert("修改成功")
|
|
})
|
|
.catch(error => {
|
|
console.error('更新登記人失敗:', error);
|
|
this.$toast?.error?.('更新失敗,請檢查數據');
|
|
});
|
|
},
|
|
//--------------------------------登記人相關函數 end
|
|
|
|
//--------------------------------牌位資料相關函數 Start
|
|
saveCreatePositionRecordMethod() {
|
|
// 校驗必須欄位
|
|
if (!this.form.createPositionRecord.registrantCode) {
|
|
alert('請先填寫登記人資料並且送出保存!');
|
|
return;
|
|
}
|
|
|
|
axios.post(HTTP_HOST + 'api/ancestraltablet/pw/create', this.form.createPositionRecord)
|
|
.then(res => {
|
|
if (res.data && res.data.message) {
|
|
alert(res.data.message);
|
|
} else {
|
|
alert('保存成功');
|
|
}
|
|
// 成功後可以關閉彈出視窗或清空表單
|
|
//this.showCreatePWFlag = false;
|
|
})
|
|
.catch(err => {
|
|
console.error('保存失敗:', err);
|
|
alert('保存失敗,請檢查伺服器日誌');
|
|
});
|
|
},
|
|
updateCreatePositionRecordMethod() {
|
|
// 校驗必須欄位
|
|
if (!this.form.createPositionRecord.recordId) {
|
|
alert('不存在牌位資料,無法更新');
|
|
return;
|
|
}
|
|
|
|
axios.post(HTTP_HOST + 'api/ancestraltablet/pw/update', this.form.createPositionRecord)
|
|
.then(res => {
|
|
if (res.data && res.data.message) {
|
|
alert(res.data.message);
|
|
} else {
|
|
alert('牌位資料更新成功');
|
|
}
|
|
// 成功後可以關閉彈出視窗或清空表單
|
|
//this.showCreatePWFlag = false;
|
|
})
|
|
.catch(err => {
|
|
alert('更新失敗:', err);
|
|
});
|
|
},
|
|
//--------------------------------牌位資料相關函數 end
|
|
async loadStatusList() {
|
|
//獲取狀態列表
|
|
try {
|
|
const response = await axios.get(`${HTTP_HOST}api/ancestraltablet/status/list`);
|
|
this.statusList = response.data;
|
|
} catch (err) {
|
|
console.error('獲取狀態列表失敗', err);
|
|
}
|
|
}
|
|
|
|
},
|
|
watch: {
|
|
|
|
},
|
|
mounted() {
|
|
this.getAreaListMethod();
|
|
this.loadStatusList();
|
|
}
|
|
});
|
|
</script>
|
|
<style>
|
|
.tree, .tree ul {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding-left: 1rem;
|
|
}
|
|
.toggle-icon {
|
|
cursor: pointer;
|
|
user-select: none;
|
|
width: 1rem;
|
|
display: inline-block;
|
|
color: #007bff;
|
|
}
|
|
.region-item-label {
|
|
cursor: pointer;
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
display: inline-block;
|
|
}
|
|
.region-item-label.selected {
|
|
background-color: #eaf4ff;
|
|
color: #0d6efd;
|
|
font-weight: bold;
|
|
}
|
|
.grid-container {
|
|
display: grid;
|
|
grid-template-columns: repeat(10, 150px); /* 6列 */
|
|
grid-auto-rows: 150px; /* 行高 */
|
|
gap: 10px;
|
|
}
|
|
/* 可用(綠色) */
|
|
.status-available {
|
|
background-color: #d4edda;
|
|
border-color: #28a745;
|
|
}
|
|
|
|
/* 維護中(黃色) */
|
|
.status-maintenance {
|
|
background-color: #fff3cd;
|
|
border-color: #ffc107;
|
|
}
|
|
|
|
/* 已使用(灰色) */
|
|
.status-used {
|
|
background-color: #e2e3e5;
|
|
border-color: #6c757d;
|
|
}
|
|
.grid-item {
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
box-shadow: 1px 1px 3px rgba(0,0,0,0.1);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.position-name {
|
|
background-color: #f0f0f0;
|
|
padding: 4px 8px;
|
|
font-weight: bold;
|
|
font-size: 14px;
|
|
text-align: center;
|
|
border-bottom: 1px solid #ddd;
|
|
}
|
|
|
|
.position-content {
|
|
flex-grow: 1;
|
|
padding: 3px;
|
|
font-size: 12px;
|
|
color: #666;
|
|
}
|
|
</style>
|
|
</asp:Content> |