From 450f4d99cc5c24bc9b5da437ec0a1e08fe1f4bf9 Mon Sep 17 00:00:00 2001 From: larry2701 Date: Tue, 3 Jun 2025 09:27:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=8C=E5=8F=B0=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Backstage/fee_list.html | 141 +++++++++++++++++------ Backstage/login.html | 30 +++-- Backstage/parcel_list.html | 33 +++++- Backstage/repair_edit.html | 2 +- Backstage/repair_list.html | 222 +++++++++++++++++++++++++++++++++++++ Backstage/sidebar.html | 2 +- 6 files changed, 387 insertions(+), 43 deletions(-) create mode 100644 Backstage/repair_list.html diff --git a/Backstage/fee_list.html b/Backstage/fee_list.html index b6dbc92..0fa0fdc 100644 --- a/Backstage/fee_list.html +++ b/Backstage/fee_list.html @@ -15,6 +15,16 @@ .container.mt-4 { flex-grow: 1; } + /* Ensure placeholders are visible for date inputs when not focused */ + input[type="date"]::before { + content: attr(placeholder); + color: #6c757d; /* Bootstrap's default placeholder color */ + margin-right: 0.5em; + } + input[type="date"]:focus::before, + input[type="date"]:valid::before { + display: none; + } @@ -28,14 +38,14 @@ -
-
+
+
-
+
-
+
-
+
+ +
+
+ +
+
-
+
+
@@ -60,6 +77,7 @@ 應繳金額 繳費項目 繳費單號 + 繳費截止日 繳費狀態 操作 @@ -68,6 +86,10 @@ +
+
目前列表總金額:$0
+
+
1 頁,共 1
@@ -91,7 +113,9 @@ { id: 4, billingDate: "2025/03/01", payer: "李四 (A102)", amountDue: 500, feeItem: "公設修繕分攤", billNumber: "FEE20250301003", paymentStatus: "已逾期", notes: "多次催繳未付", dueDate: "2025/03/15" }, { id: 5, billingDate: "2025/05/05", payer: "張三 (D301)", amountDue: 150, feeItem: "腳踏車位租金", billNumber: "FEE20250505001", paymentStatus: "待繳費", notes: "", dueDate: "2025/05/20" }, { id: 6, billingDate: "2025/05/10", payer: "趙六 (B205)", amountDue: 2000, feeItem: "預繳上半年管理費", billNumber: "FEE20250510001", paymentStatus: "已繳費", notes: "一次付清", dueDate: "2025/05/25" }, - { id: 7, billingDate: "2025/04/15", payer: "孫七 (E101)", amountDue: 750, feeItem: "社區活動費", billNumber: "FEE20250415001", paymentStatus: "待繳費", notes: "母親節活動", dueDate: "2025/04/30" } + { id: 7, billingDate: "2025/04/15", payer: "孫七 (E101)", amountDue: 750, feeItem: "社區活動費", billNumber: "FEE20250415001", paymentStatus: "待繳費", notes: "母親節活動", dueDate: "2025/04/30" }, + { id: 8, billingDate: "2025/06/01", payer: "吳九 (F202)", amountDue: 1200, feeItem: "管理費 2025年6月", billNumber: "FEE20250601001", paymentStatus: "待繳費", notes: "", dueDate: "" }, // Example with empty due date + { id: 9, billingDate: "2025/06/05", payer: "鄭十 (G303)", amountDue: 350, feeItem: "游泳池維護", billNumber: "FEE20250605001", paymentStatus: "待繳費", notes: "", dueDate: "2025/06/15" } ]; function renderTable(dataToRender) { @@ -100,19 +124,22 @@ const start = (currentPage - 1) * pageSize; const pageData = dataToRender.slice(start, start + pageSize); + let currentListTotal = 0; + dataToRender.forEach(fee => { + currentListTotal += fee.amountDue; + }); + const totalAmountDisplay = document.getElementById("currentListTotalAmount"); + if (totalAmountDisplay) { + totalAmountDisplay.textContent = '$' + currentListTotal; + } + pageData.forEach(fee => { const row = document.createElement("tr"); - let statusBadgeClass = 'bg-secondary'; // Default badge + let statusBadgeClass = 'bg-secondary'; switch (fee.paymentStatus) { - case '待繳費': - statusBadgeClass = 'bg-warning text-dark'; - break; - case '已繳費': - statusBadgeClass = 'bg-success'; - break; - case '已逾期': - statusBadgeClass = 'bg-danger'; - break; + case '待繳費': statusBadgeClass = 'bg-warning text-dark'; break; + case '已繳費': statusBadgeClass = 'bg-success'; break; + case '已逾期': statusBadgeClass = 'bg-danger'; break; } row.innerHTML = ` @@ -123,6 +150,7 @@ $${fee.amountDue} ${fee.feeItem} ${fee.billNumber} + ${fee.dueDate || '---'} ${fee.paymentStatus} 編輯 @@ -160,6 +188,10 @@ if (totalPagesDisplay) totalPagesDisplay.textContent = 1; if (prevButton) prevButton.disabled = true; if (nextButton) nextButton.disabled = true; + const totalAmountDisplay = document.getElementById("currentListTotalAmount"); + if (totalAmountDisplay) { + totalAmountDisplay.textContent = '$0'; + } } } @@ -184,19 +216,57 @@ const payerInput = document.getElementById("searchPayer").value.toLowerCase(); const billNumberInput = document.getElementById("searchBillNumber").value.toLowerCase(); const paymentStatusInput = document.getElementById("searchPaymentStatus").value; + const dueDateStartInput = document.getElementById("searchDueDateStart").value; // "YYYY-MM-DD" or "" + const dueDateEndInput = document.getElementById("searchDueDateEnd").value; // "YYYY-MM-DD" or "" - // Load from localStorage if available const storedFees = JSON.parse(localStorage.getItem('fees_data_temp')); if (storedFees) { fees_data = storedFees; } + currentFilteredData = fees_data.filter(fee => { + const payerMatch = fee.payer.toLowerCase().includes(payerInput); + const billNumberMatch = fee.billNumber.toLowerCase().includes(billNumberInput); + const statusMatch = (paymentStatusInput === "" || fee.paymentStatus === paymentStatusInput); - currentFilteredData = fees_data.filter(fee => - fee.payer.toLowerCase().includes(payerInput) && - fee.billNumber.toLowerCase().includes(billNumberInput) && - (paymentStatusInput === "" || fee.paymentStatus === paymentStatusInput) - ); + let dateRangeMatch = true; + const feeDueDateStr = fee.dueDate; // format "YYYY/MM/DD" or empty + + if (dueDateStartInput || dueDateEndInput) { // Apply date filter only if at least one date is entered + if (!feeDueDateStr || feeDueDateStr.trim() === "") { // If fee has no valid due date string + dateRangeMatch = false; + } else { + try { + // Convert fee's due date "YYYY/MM/DD" to a Date object + const itemDate = new Date(feeDueDateStr.replace(/\//g, '-')); + if (isNaN(itemDate.getTime())) { // Check for invalid date + dateRangeMatch = false; + } else { + itemDate.setHours(0, 0, 0, 0); // Normalize to compare dates only + + if (dueDateStartInput) { + const startDate = new Date(dueDateStartInput); // Input is "YYYY-MM-DD" + startDate.setHours(0, 0, 0, 0); + if (itemDate < startDate) { + dateRangeMatch = false; + } + } + if (dateRangeMatch && dueDateEndInput) { // Only check end if start was okay + const endDate = new Date(dueDateEndInput); // Input is "YYYY-MM-DD" + endDate.setHours(0, 0, 0, 0); + if (itemDate > endDate) { + dateRangeMatch = false; + } + } + } + } catch (e) { + console.error("Error parsing due date:", feeDueDateStr, e); + dateRangeMatch = false; // Error during parsing, treat as non-match + } + } + } + return payerMatch && billNumberMatch && statusMatch && dateRangeMatch; + }); currentPage = 1; renderTable(currentFilteredData); } @@ -215,27 +285,29 @@ } const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id)); fees_data = fees_data.filter(fee => !idsToDelete.includes(fee.id)); - localStorage.setItem('fees_data_temp', JSON.stringify(fees_data)); // Update localStorage + localStorage.setItem('fees_data_temp', JSON.stringify(fees_data)); - performSearch(); // Re-filter and re-render + performSearch(); } function deleteFee(id) { if (!confirm("確定要刪除此筆繳費通知嗎?")) return; fees_data = fees_data.filter(fee => fee.id !== id); - localStorage.setItem('fees_data_temp', JSON.stringify(fees_data)); // Update localStorage + localStorage.setItem('fees_data_temp', JSON.stringify(fees_data)); - performSearch(); // Re-filter and re-render + performSearch(); } function exportFees() { const payerInput = document.getElementById("searchPayer").value.toLowerCase(); const billNumberInput = document.getElementById("searchBillNumber").value.toLowerCase(); const paymentStatusInput = document.getElementById("searchPaymentStatus").value; + // Note: Due date range from inputs could also be used to pre-filter dataToExport + // but current logic exports based on `currentFilteredData` if any filter is active, + // which now includes date range. let dataToExport = fees_data; - // If any search criteria is active, export filtered data - if (payerInput || billNumberInput || paymentStatusInput) { + if (payerInput || billNumberInput || paymentStatusInput || document.getElementById("searchDueDateStart").value || document.getElementById("searchDueDateEnd").value) { dataToExport = currentFilteredData; } @@ -244,7 +316,7 @@ return; } - let csvContent = "data:text/csv;charset=utf-8,\uFEFF"; // \uFEFF for BOM + let csvContent = "data:text/csv;charset=utf-8,\uFEFF"; csvContent += "ID,開單日期,住戶/繳費人,應繳金額,繳費項目,繳費單號,繳費狀態,繳費截止日,備註,提醒次數\n"; dataToExport.forEach(fee => { const cleanPayer = `"${fee.payer.replace(/"/g, '""')}"`; @@ -267,11 +339,16 @@ link.click(); document.body.removeChild(link); - alert(`準備匯出 ${dataToExport.length} 筆繳費資料(${payerInput || billNumberInput || paymentStatusInput ? "依搜尋條件" : "全部"})`); + const filterActive = payerInput || billNumberInput || paymentStatusInput || document.getElementById("searchDueDateStart").value || document.getElementById("searchDueDateEnd").value; + alert(`準備匯出 ${dataToExport.length} 筆繳費資料(${filterActive ? "依搜尋條件" : "全部"})`); } - // Initial load: apply no filters (show all) and render document.addEventListener('DOMContentLoaded', () => { + // Initialize date input types correctly if they have values (e.g. from browser cache) + ['searchDueDateStart', 'searchDueDateEnd'].forEach(id => { + const el = document.getElementById(id); + if (el.value) el.type = 'date'; + }); performSearch(); }); diff --git a/Backstage/login.html b/Backstage/login.html index 9f8df0d..0314dd5 100644 --- a/Backstage/login.html +++ b/Backstage/login.html @@ -11,27 +11,43 @@ + 美工圖 +

社區通 後台登入

-
+
- +
- +
+ + \ No newline at end of file diff --git a/Backstage/parcel_list.html b/Backstage/parcel_list.html index 7419cc5..33b67a6 100644 --- a/Backstage/parcel_list.html +++ b/Backstage/parcel_list.html @@ -68,6 +68,10 @@ +
+
目前列表總代收金額:$0
+
+
1 頁,共 1
@@ -100,6 +104,16 @@ const start = (currentPage - 1) * pageSize; const pageData = dataToRender.slice(start, start + pageSize); + // Calculate and display total amount to collect for the current filtered list + let currentListTotalCollect = 0; + dataToRender.forEach(pkg => { + currentListTotalCollect += pkg.amountToCollect; + }); + const totalAmountCollectDisplay = document.getElementById("currentListTotalAmountToCollect"); + if (totalAmountCollectDisplay) { + totalAmountCollectDisplay.textContent = '$' + currentListTotalCollect; + } + pageData.forEach(pkg => { const row = document.createElement("tr"); let statusBadgeClass = 'bg-secondary'; // Default badge @@ -161,6 +175,11 @@ if (totalPagesDisplay) totalPagesDisplay.textContent = 1; if (prevButton) prevButton.disabled = true; if (nextButton) nextButton.disabled = true; + // Also reset total amount to collect if no items + const totalAmountCollectDisplay = document.getElementById("currentListTotalAmountToCollect"); + if (totalAmountCollectDisplay) { + totalAmountCollectDisplay.textContent = '$0'; + } } } @@ -186,6 +205,13 @@ const packageNumberInput = document.getElementById("searchPackageNumber").value.toLowerCase(); const statusInput = document.getElementById("searchStatus").value; + // In a real app, you might fetch from localStorage or server here if data can be modified elsewhere. + // For this example, using the in-memory packages_data. + // const storedPackages = JSON.parse(localStorage.getItem('packages_data_temp')); + // if (storedPackages) { + // packages_data = storedPackages; + // } + currentFilteredData = packages_data.filter(pkg => pkg.recipient.toLowerCase().includes(recipientInput) && pkg.packageNumber.toLowerCase().includes(packageNumberInput) && @@ -209,6 +235,7 @@ } const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id)); packages_data = packages_data.filter(pkg => !idsToDelete.includes(pkg.id)); + // localStorage.setItem('packages_data_temp', JSON.stringify(packages_data)); // If using localStorage performSearch(); // Re-filter and re-render } @@ -216,6 +243,7 @@ function deletePackage(id) { if (!confirm("確定要刪除此包裹紀錄嗎?")) return; packages_data = packages_data.filter(pkg => pkg.id !== id); + // localStorage.setItem('packages_data_temp', JSON.stringify(packages_data)); // If using localStorage performSearch(); // Re-filter and re-render } @@ -226,7 +254,6 @@ const statusInput = document.getElementById("searchStatus").value; let dataToExport = packages_data; - // If any search criteria is active, export filtered data if (recipientInput || packageNumberInput || statusInput) { dataToExport = currentFilteredData; } @@ -261,7 +288,9 @@ } // Initial load: apply no filters (show all) and render - performSearch(); + document.addEventListener('DOMContentLoaded', () => { + performSearch(); + }); diff --git a/Backstage/repair_edit.html b/Backstage/repair_edit.html index d28793c..096385a 100644 --- a/Backstage/repair_edit.html +++ b/Backstage/repair_edit.html @@ -48,7 +48,7 @@
- 返回列表 + 返回列表
diff --git a/Backstage/repair_list.html b/Backstage/repair_list.html new file mode 100644 index 0000000..ecafca6 --- /dev/null +++ b/Backstage/repair_list.html @@ -0,0 +1,222 @@ + + + + + 水電報修列表 + + + + + +
+
+

水電報修列表

+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + + + + + + + + + + + + + + + + +
報修類型住戶姓名房號報修說明送出時間維修費用狀態操作
+ +
+
列表總維修費用:$0
+
+ +
+
1 頁,共 1
+
+ + +
+
+
+ + + + + \ No newline at end of file diff --git a/Backstage/sidebar.html b/Backstage/sidebar.html index 9632bda..72e7ef3 100644 --- a/Backstage/sidebar.html +++ b/Backstage/sidebar.html @@ -203,7 +203,7 @@
    -
  • +
  • 報修申請 99