後台調整
This commit is contained in:
parent
43a0a8ac93
commit
f027c4e523
74
Backstage/carousel_ads_add.html
Normal file
74
Backstage/carousel_ads_add.html
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>新增輪播廣告</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2 class="mb-4">新增輪播廣告</h2>
|
||||||
|
<form id="adForm">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="title" class="form-label">廣告標題</label>
|
||||||
|
<input type="text" class="form-control" id="title" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="content" class="form-label">廣告內容</label>
|
||||||
|
<textarea class="form-control" id="content" rows="3" required></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="image" class="form-label">圖片上傳</label>
|
||||||
|
<input type="file" class="form-control" id="image" accept="image/*" required>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="startDate" class="form-label">開始日期</label>
|
||||||
|
<input type="date" class="form-control" id="startDate" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="endDate" class="form-label">結束日期</label>
|
||||||
|
<input type="date" class="form-control" id="endDate" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="status" class="form-label">狀態</label>
|
||||||
|
<select class="form-select" id="status" required>
|
||||||
|
<option value="">請選擇</option>
|
||||||
|
<option value="啟用">啟用</option>
|
||||||
|
<option value="停用">停用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="sortOrder" class="form-label">排序</label>
|
||||||
|
<input type="number" class="form-control" id="sortOrder" min="1" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-success">新增廣告</button>
|
||||||
|
<a href="carousel_ads_list.html" class="btn btn-secondary ms-2">取消</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("adForm").addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("title", document.getElementById("title").value);
|
||||||
|
formData.append("content", document.getElementById("content").value);
|
||||||
|
formData.append("image", document.getElementById("image").files[0]);
|
||||||
|
formData.append("startDate", document.getElementById("startDate").value);
|
||||||
|
formData.append("endDate", document.getElementById("endDate").value);
|
||||||
|
formData.append("status", document.getElementById("status").value);
|
||||||
|
formData.append("sortOrder", document.getElementById("sortOrder").value);
|
||||||
|
|
||||||
|
console.log("新增的廣告資料:");
|
||||||
|
for (let [key, value] of formData.entries()) {
|
||||||
|
console.log(key + ": ", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
alert("廣告已新增(實際需串接 API 上傳圖檔與資料)");
|
||||||
|
window.location.href = "ad_list.html";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
94
Backstage/carousel_ads_edit.html
Normal file
94
Backstage/carousel_ads_edit.html
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>編輯輪播廣告</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
.preview-img {
|
||||||
|
max-width: 200px;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2 class="mb-4">編輯輪播廣告</h2>
|
||||||
|
<form id="editForm">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="title" class="form-label">廣告標題</label>
|
||||||
|
<input type="text" class="form-control" id="title" value="社區中秋禮盒廣告" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="content" class="form-label">廣告內容</label>
|
||||||
|
<textarea class="form-control" id="content" rows="3" required>歡迎訂購社區專屬中秋禮盒!</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="image" class="form-label">更換圖片(選填)</label>
|
||||||
|
<input type="file" class="form-control" id="image" accept="image/*">
|
||||||
|
<img id="currentImage" src="https://via.placeholder.com/300x150?text=廣告2" alt="目前圖片" class="preview-img">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="startDate" class="form-label">開始日期</label>
|
||||||
|
<input type="date" class="form-control" id="startDate" value="2025-05-20" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="endDate" class="form-label">結束日期</label>
|
||||||
|
<input type="date" class="form-control" id="endDate" value="2099-12-31" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="status" class="form-label">狀態</label>
|
||||||
|
<select class="form-select" id="status" required>
|
||||||
|
<option value="">請選擇</option>
|
||||||
|
<option value="啟用">啟用</option>
|
||||||
|
<option value="停用" selected>停用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="sortOrder" class="form-label">排序</label>
|
||||||
|
<input type="number" class="form-control" id="sortOrder" value="2" min="1" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">儲存修改</button>
|
||||||
|
<a href="carousel_ads_list.html" class="btn btn-secondary ms-2">取消</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("editForm").addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("title", document.getElementById("title").value);
|
||||||
|
formData.append("content", document.getElementById("content").value);
|
||||||
|
if (document.getElementById("image").files[0]) {
|
||||||
|
formData.append("image", document.getElementById("image").files[0]);
|
||||||
|
}
|
||||||
|
formData.append("startDate", document.getElementById("startDate").value);
|
||||||
|
formData.append("endDate", document.getElementById("endDate").value);
|
||||||
|
formData.append("status", document.getElementById("status").value);
|
||||||
|
formData.append("sortOrder", document.getElementById("sortOrder").value);
|
||||||
|
|
||||||
|
console.log("修改後的廣告資料:");
|
||||||
|
for (let [key, value] of formData.entries()) {
|
||||||
|
console.log(key + ": ", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
alert("廣告資料已儲存(實際需串接 API)");
|
||||||
|
window.location.href = "ad_list.html";
|
||||||
|
});
|
||||||
|
|
||||||
|
// 圖片預覽功能
|
||||||
|
document.getElementById("image").addEventListener("change", function () {
|
||||||
|
const file = this.files[0];
|
||||||
|
if (file) {
|
||||||
|
const imgPreview = document.getElementById("currentImage");
|
||||||
|
imgPreview.src = URL.createObjectURL(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
161
Backstage/carousel_ads_list.html
Normal file
161
Backstage/carousel_ads_list.html
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>輪播廣告列表</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
.status-badge {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.4em 0.7em;
|
||||||
|
}
|
||||||
|
.ad-thumbnail {
|
||||||
|
width: 120px;
|
||||||
|
height: 60px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.sort-input {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h2>輪播廣告列表</h2>
|
||||||
|
<a href="carousel_ads_add.html" class="btn btn-success">+ 新增廣告</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 搜尋與控制列 -->
|
||||||
|
<div class="row g-2 mb-3 align-items-end">
|
||||||
|
<div class="col-sm-6 col-md-4 col-lg-3">
|
||||||
|
<input type="text" id="searchName" class="form-control" placeholder="搜尋標題" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-2 col-lg-2">
|
||||||
|
<button class="btn btn-outline-primary w-100 rounded-pill" onclick="window.alert('依據查詢關鍵字列出');">搜尋</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 mt-2 d-flex justify-content-between align-items-center flex-wrap">
|
||||||
|
<div class="d-flex gap-2 mb-2">
|
||||||
|
<button class="btn btn-danger" onclick="deleteSelected()">刪除選取</button>
|
||||||
|
<button class="btn btn-primary" onclick="saveSortChanges()">儲存排序變更</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="min-width: 200px;">
|
||||||
|
<select id="sortOrder" class="form-select" onchange="sortTable()">
|
||||||
|
<option value="asc">依排序:由小到大</option>
|
||||||
|
<option value="desc">依排序:由大到小</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="adTable" class="table table-bordered table-hover align-middle">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th><input type="checkbox" onclick="toggleAll(this)" /></th>
|
||||||
|
<th>縮圖</th>
|
||||||
|
<th>標題</th>
|
||||||
|
<th>期間</th>
|
||||||
|
<th>狀態</th>
|
||||||
|
<th>排序</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" /></td>
|
||||||
|
<td><img src="https://via.placeholder.com/300x150?text=廣告1" class="ad-thumbnail" alt="廣告縮圖" /></td>
|
||||||
|
<td>社區防火宣導</td>
|
||||||
|
<td>2023/05/20 - 2024/12/20(過期)</td>
|
||||||
|
<td><span class="badge bg-success status-badge">啟用</span></td>
|
||||||
|
<td><input type="number" class="form-control form-control-sm sort-input" value="1" /></td>
|
||||||
|
<td>
|
||||||
|
<a href="carousel_ads_edit.html?id=1" class="btn btn-outline-secondary btn-sm">編輯</a>
|
||||||
|
<button class="btn btn-outline-danger btn-sm" onclick="if(confirm('確定要刪除這則廣告嗎?')) this.closest('tr').remove();">刪除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" /></td>
|
||||||
|
<td><img src="https://via.placeholder.com/300x150?text=廣告2" class="ad-thumbnail" alt="廣告縮圖" /></td>
|
||||||
|
<td>社區中秋禮盒廣告</td>
|
||||||
|
<td>2025/05/20 - 2099/12/31(顯示中)</td>
|
||||||
|
<td><span class="badge bg-secondary status-badge">停用</span></td>
|
||||||
|
<td><input type="number" class="form-control form-control-sm sort-input" value="2" /></td>
|
||||||
|
<td>
|
||||||
|
<a href="carousel_ads_edit.html?id=2" class="btn btn-outline-secondary btn-sm">編輯</a>
|
||||||
|
<button class="btn btn-outline-danger btn-sm" onclick="if(confirm('確定要刪除這則廣告嗎?')) this.closest('tr').remove();">刪除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" /></td>
|
||||||
|
<td><img src="https://via.placeholder.com/300x150?text=廣告2" class="ad-thumbnail" alt="廣告縮圖" /></td>
|
||||||
|
<td>社區中秋禮盒廣告</td>
|
||||||
|
<td>2025/05/20 - 2099/12/31(未到)</td>
|
||||||
|
<td><span class="badge bg-secondary status-badge">停用</span></td>
|
||||||
|
<td><input type="number" class="form-control form-control-sm sort-input" value="3" /></td>
|
||||||
|
<td>
|
||||||
|
<a href="carousel_ads_edit.html?id=2" class="btn btn-outline-secondary btn-sm">編輯</a>
|
||||||
|
<button class="btn btn-outline-danger btn-sm" onclick="if(confirm('確定要刪除這則廣告嗎?')) this.closest('tr').remove();">刪除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- 更多資料列可加在這裡 -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>第 <span>1</span> 頁,共 <span>1</span> 頁</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary me-1">上一頁</button>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary">下一頁</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
function toggleAll(source) {
|
||||||
|
const checkboxes = document.querySelectorAll('.row-checkbox');
|
||||||
|
checkboxes.forEach(cb => (cb.checked = source.checked));
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteSelected() {
|
||||||
|
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
|
||||||
|
if (checkboxes.length === 0) {
|
||||||
|
alert('請先勾選要刪除的廣告');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!confirm(`確定要刪除 ${checkboxes.length} 則廣告嗎?`)) return;
|
||||||
|
checkboxes.forEach(cb => cb.closest('tr').remove());
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveSortChanges() {
|
||||||
|
const rows = document.querySelectorAll('#adTable tbody tr');
|
||||||
|
rows.forEach(row => {
|
||||||
|
const title = row.children[2].textContent.trim();
|
||||||
|
const newSort = row.querySelector('.sort-input').value;
|
||||||
|
console.log(`廣告:「${title}」新排序:${newSort}`);
|
||||||
|
// 可在此加上 fetch/ajax 傳到後端
|
||||||
|
});
|
||||||
|
alert('排序變更已儲存(模擬)');
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortTable() {
|
||||||
|
const order = document.getElementById('sortOrder').value;
|
||||||
|
const table = document.getElementById('adTable');
|
||||||
|
const tbody = table.querySelector('tbody');
|
||||||
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||||
|
|
||||||
|
rows.sort((a, b) => {
|
||||||
|
const aValue = parseInt(a.querySelector('.sort-input').value);
|
||||||
|
const bValue = parseInt(b.querySelector('.sort-input').value);
|
||||||
|
return order === 'asc' ? aValue - bValue : bValue - aValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
rows.forEach(row => tbody.appendChild(row));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
117
Backstage/feedback_edit.html
Normal file
117
Backstage/feedback_edit.html
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>意見回饋詳情</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
.form-control-plaintext {
|
||||||
|
border: 1px solid #ced4da; /* Optional: add a light border to plaintext for visual grouping */
|
||||||
|
padding: .375rem .75rem;
|
||||||
|
background-color: #e9ecef; /* Light gray to indicate non-editable */
|
||||||
|
}
|
||||||
|
textarea.form-control-plaintext {
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2 class="mb-4">意見回饋詳情</h2>
|
||||||
|
<form id="feedbackDetailForm">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label"><strong>ID</strong></label>
|
||||||
|
<input type="text" class="form-control-plaintext" id="feedbackIdDisplay" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label"><strong>提交者</strong></label>
|
||||||
|
<input type="text" class="form-control-plaintext" id="submitterDisplay" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label"><strong>意見類型</strong></label>
|
||||||
|
<input type="text" class="form-control-plaintext" id="typeDisplay" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label"><strong>提交時間</strong></label>
|
||||||
|
<input type="text" class="form-control-plaintext" id="timeDisplay" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label"><strong>內容</strong></label>
|
||||||
|
<textarea class="form-control-plaintext" id="contentDisplay" rows="6" readonly></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="statusSelect" class="form-label"><strong>處理狀態</strong></label>
|
||||||
|
<select class="form-select" id="statusSelect" required>
|
||||||
|
<option value="未讀">未讀</option>
|
||||||
|
<option value="需處理">需處理</option>
|
||||||
|
<option value="已處理">已處理</option>
|
||||||
|
<option value="不需處理">不需處理</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">更新狀態</button>
|
||||||
|
<a href="feedback_list.html" class="btn btn-secondary ms-2">返回列表</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Sample data - in a real application, this would come from a backend or be passed from the list page.
|
||||||
|
// This structure should match what's used in feedback_admin_list.html
|
||||||
|
const allFeedbackItems = [
|
||||||
|
{ id: 1, submitter: "A101住戶", type: "建議", content: "社區中庭可以增加一些兒童遊樂設施,讓孩子們有更多玩樂的空間。", submissionTime: "2025/05/20 10:30", processingStatus: "未讀", anonymous: false },
|
||||||
|
{ id: 2, submitter: "匿名", type: "問題", content: "地下室停車場B區靠近出口的燈光好像壞了,晚上有點暗,希望能盡快修復。", submissionTime: "2025/05/19 15:00", processingStatus: "已處理", anonymous: true },
|
||||||
|
{ id: 3, submitter: "C305住戶 (林小姐)", type: "其他", content: "非常感謝上週管理員協助代收重要包裹,並且及時通知,服務很棒!", submissionTime: "2025/05/21 09:00", processingStatus: "不需處理", anonymous: false },
|
||||||
|
{ id: 4, submitter: "B202住戶", type: "建議", content: "建議圖書室可以增加一些最新的雜誌和報紙。", submissionTime: "2025/05/21 11:15", processingStatus: "需處理", anonymous: false },
|
||||||
|
{ id: 5, submitter: "匿名", type: "問題", content: "一樓大廳的飲水機好像出水有點小,麻煩檢查一下。", submissionTime: "2025/05/22 14:00", processingStatus: "未讀", anonymous: true },
|
||||||
|
{ id: 6, submitter: "D110住戶 (王先生)", type: "建議", content: "垃圾集中處理區的分類標示可以再更清楚一點。", submissionTime: "2025/05/18 08:20", processingStatus: "已處理", anonymous: false },
|
||||||
|
{ id: 7, submitter: "匿名", type: "其他", content: "週末的社區電影院活動很棒,希望未來能多舉辦。", submissionTime: "2025/05/17 19:30", processingStatus: "不需處理", anonymous: true },
|
||||||
|
{ id: 8, submitter: "E201住戶", type: "問題", content: "健身房的跑步機有異常聲音,請派人檢修。", submissionTime: "2025/05/23 09:00", processingStatus: "需處理", anonymous: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const feedbackId = parseInt(urlParams.get('id'));
|
||||||
|
|
||||||
|
if (!feedbackId) {
|
||||||
|
alert('未指定意見回饋 ID!');
|
||||||
|
window.location.href = 'feedback_list.html';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const feedbackItem = allFeedbackItems.find(item => item.id === feedbackId);
|
||||||
|
|
||||||
|
if (feedbackItem) {
|
||||||
|
document.getElementById('feedbackIdDisplay').value = feedbackItem.id;
|
||||||
|
document.getElementById('submitterDisplay').value = feedbackItem.anonymous ? '匿名' : feedbackItem.submitter;
|
||||||
|
document.getElementById('typeDisplay').value = feedbackItem.type;
|
||||||
|
document.getElementById('timeDisplay').value = feedbackItem.submissionTime;
|
||||||
|
document.getElementById('contentDisplay').value = feedbackItem.content;
|
||||||
|
document.getElementById('statusSelect').value = feedbackItem.processingStatus;
|
||||||
|
} else {
|
||||||
|
alert('找不到該意見回饋!');
|
||||||
|
window.location.href = 'feedback_admin_list.html';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("feedbackDetailForm").addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const feedbackId = document.getElementById('feedbackIdDisplay').value;
|
||||||
|
const newStatus = document.getElementById("statusSelect").value;
|
||||||
|
|
||||||
|
console.log("更新意見回饋狀態:");
|
||||||
|
console.log("ID:", feedbackId);
|
||||||
|
console.log("新狀態:", newStatus);
|
||||||
|
|
||||||
|
// Here you would typically send this data to a backend API
|
||||||
|
// For demonstration, we'll just show an alert and redirect.
|
||||||
|
|
||||||
|
alert(`意見 ID ${feedbackId} 的狀態已更新為 "${newStatus}" (此為模擬操作)`);
|
||||||
|
window.location.href = "feedback_admin_list.html";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
171
Backstage/feedback_list.html
Normal file
171
Backstage/feedback_list.html
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>意見回饋管理</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
.content-summary {
|
||||||
|
max-width: 300px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="d-flex justify-content-between mb-3">
|
||||||
|
<h2>意見回饋列表</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-2 mb-3 align-items-center">
|
||||||
|
<div class="col-sm-6 col-md-3 col-lg-3">
|
||||||
|
<input type="text" id="searchContent" class="form-control" placeholder="搜尋內容摘要">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-3 col-lg-2">
|
||||||
|
<select id="filterType" class="form-select">
|
||||||
|
<option value="">所有意見類型</option>
|
||||||
|
<option value="建議">建議</option>
|
||||||
|
<option value="問題">問題</option>
|
||||||
|
<option value="其他">其他</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-3 col-lg-2">
|
||||||
|
<select id="filterStatus" class="form-select">
|
||||||
|
<option value="">所有處理狀態</option>
|
||||||
|
<option value="未讀">未讀</option>
|
||||||
|
<option value="需處理">需處理</option>
|
||||||
|
<option value="已處理">已處理</option>
|
||||||
|
<option value="不需處理">不需處理</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-3 col-lg-2">
|
||||||
|
<button class="btn btn-outline-primary w-100 rounded-pill" onclick="applyFilters()">搜尋/篩選</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>提交者</th>
|
||||||
|
<th>意見類型</th>
|
||||||
|
<th>內容摘要</th>
|
||||||
|
<th>提交時間</th>
|
||||||
|
<th>處理狀態</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="feedbackTableBody"></tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>第 <span id="currentPage">1</span> 頁,共 <span id="totalPages">1</span> 頁</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary me-1" id="prevBtn">上一頁</button>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary" id="nextBtn">下一頁</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
const allFeedbackItems = [
|
||||||
|
{ id: 1, submitter: "A101住戶", type: "建議", content: "社區中庭可以增加一些兒童遊樂設施,讓孩子們有更多玩樂的空間。", submissionTime: "2025/05/20 10:30", processingStatus: "未讀", anonymous: false },
|
||||||
|
{ id: 2, submitter: "匿名", type: "問題", content: "地下室停車場B區靠近出口的燈光好像壞了,晚上有點暗,希望能盡快修復。", submissionTime: "2025/05/19 15:00", processingStatus: "已處理", anonymous: true },
|
||||||
|
{ id: 3, submitter: "C305住戶 (林小姐)", type: "其他", content: "非常感謝上週管理員協助代收重要包裹,並且及時通知,服務很棒!", submissionTime: "2025/05/21 09:00", processingStatus: "不需處理", anonymous: false },
|
||||||
|
{ id: 4, submitter: "B202住戶", type: "建議", content: "建議圖書室可以增加一些最新的雜誌和報紙。", submissionTime: "2025/05/21 11:15", processingStatus: "需處理", anonymous: false },
|
||||||
|
{ id: 5, submitter: "匿名", type: "問題", content: "一樓大廳的飲水機好像出水有點小,麻煩檢查一下。", submissionTime: "2025/05/22 14:00", processingStatus: "未讀", anonymous: true },
|
||||||
|
{ id: 6, submitter: "D110住戶 (王先生)", type: "建議", content: "垃圾集中處理區的分類標示可以再更清楚一點。", submissionTime: "2025/05/18 08:20", processingStatus: "已處理", anonymous: false },
|
||||||
|
{ id: 7, submitter: "匿名", type: "其他", content: "週末的社區電影院活動很棒,希望未來能多舉辦。", submissionTime: "2025/05/17 19:30", processingStatus: "不需處理", anonymous: true },
|
||||||
|
{ id: 8, submitter: "E201住戶", type: "問題", content: "健身房的跑步機有異常聲音,請派人檢修。", submissionTime: "2025/05/23 09:00", processingStatus: "需處理", anonymous: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
let filteredFeedbackItems = [...allFeedbackItems];
|
||||||
|
const pageSize = 5;
|
||||||
|
let currentPage = 1;
|
||||||
|
|
||||||
|
function getStatusBadge(status) {
|
||||||
|
switch (status) {
|
||||||
|
case "未讀":
|
||||||
|
return `<span class="badge bg-warning text-dark">${status}</span>`; // Yellow
|
||||||
|
case "需處理":
|
||||||
|
return `<span class="badge bg-danger">${status}</span>`; // Red
|
||||||
|
case "已處理":
|
||||||
|
return `<span class="badge bg-success">${status}</span>`; // Green
|
||||||
|
case "不需處理":
|
||||||
|
return `<span class="badge bg-secondary">${status}</span>`; // Gray
|
||||||
|
default:
|
||||||
|
return `<span class="badge bg-light text-dark">${status}</span>`; // Default/fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTable() {
|
||||||
|
const tbody = document.getElementById("feedbackTableBody");
|
||||||
|
tbody.innerHTML = "";
|
||||||
|
|
||||||
|
const startIndex = (currentPage - 1) * pageSize;
|
||||||
|
const pageItems = filteredFeedbackItems.slice(startIndex, startIndex + pageSize);
|
||||||
|
|
||||||
|
pageItems.forEach(item => {
|
||||||
|
const tr = document.createElement("tr");
|
||||||
|
const contentSummary = item.content.length > 50 ? item.content.substring(0, 50) + "..." : item.content;
|
||||||
|
const submitterDisplay = item.anonymous ? "匿名" : item.submitter;
|
||||||
|
|
||||||
|
tr.innerHTML = `
|
||||||
|
<td>${submitterDisplay}</td>
|
||||||
|
<td>${item.type}</td>
|
||||||
|
<td class="content-summary" title="${item.content}">${contentSummary}</td>
|
||||||
|
<td>${item.submissionTime}</td>
|
||||||
|
<td>${getStatusBadge(item.processingStatus)}</td>
|
||||||
|
<td><a href="feedback_edit.html?id=${item.id}" class="btn btn-outline-secondary btn-sm">查看詳情</a></td>
|
||||||
|
`;
|
||||||
|
tbody.appendChild(tr);
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(filteredFeedbackItems.length / pageSize);
|
||||||
|
document.getElementById("currentPage").textContent = currentPage;
|
||||||
|
document.getElementById("totalPages").textContent = totalPages || 1;
|
||||||
|
|
||||||
|
document.getElementById("prevBtn").disabled = currentPage === 1;
|
||||||
|
document.getElementById("nextBtn").disabled = currentPage === totalPages || totalPages === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFilters() {
|
||||||
|
const searchTerm = document.getElementById("searchContent").value.toLowerCase();
|
||||||
|
const selectedType = document.getElementById("filterType").value;
|
||||||
|
const selectedStatus = document.getElementById("filterStatus").value;
|
||||||
|
|
||||||
|
filteredFeedbackItems = allFeedbackItems.filter(item => {
|
||||||
|
const contentMatch = item.content.toLowerCase().includes(searchTerm);
|
||||||
|
const typeMatch = selectedType ? item.type === selectedType : true;
|
||||||
|
const statusMatch = selectedStatus ? item.processingStatus === selectedStatus : true;
|
||||||
|
return contentMatch && typeMatch && statusMatch;
|
||||||
|
});
|
||||||
|
currentPage = 1; // Reset to first page after filtering
|
||||||
|
renderTable();
|
||||||
|
if (filteredFeedbackItems.length === 0) {
|
||||||
|
window.alert('沒有找到符合條件的意見回饋。');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("prevBtn").addEventListener("click", () => {
|
||||||
|
if (currentPage > 1) {
|
||||||
|
currentPage--;
|
||||||
|
renderTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("nextBtn").addEventListener("click", () => {
|
||||||
|
const totalPages = Math.ceil(filteredFeedbackItems.length / pageSize);
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
currentPage++;
|
||||||
|
renderTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
renderTable(); // Initial render
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
69
Backstage/marquee_ads_add.html
Normal file
69
Backstage/marquee_ads_add.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>新增跑馬燈廣告</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2 class="mb-4">新增跑馬燈廣告</h2>
|
||||||
|
<form id="adForm">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">識別名稱 (方便管理)</label>
|
||||||
|
<input type="text" class="form-control" id="name" placeholder="例如:夏季促銷活動">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="marqueeContent" class="form-label">跑馬燈內容</label>
|
||||||
|
<textarea class="form-control" id="marqueeContent" rows="3" placeholder="請輸入要滾動顯示的文字訊息" required></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="startDate" class="form-label">開始日期</label>
|
||||||
|
<input type="date" class="form-control" id="startDate" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="endDate" class="form-label">結束日期</label>
|
||||||
|
<input type="date" class="form-control" id="endDate" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="status" class="form-label">狀態</label>
|
||||||
|
<select class="form-select" id="status" required>
|
||||||
|
<option value="">請選擇</option>
|
||||||
|
<option value="啟用">啟用</option>
|
||||||
|
<option value="停用">停用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="sortOrder" class="form-label">排序</label>
|
||||||
|
<input type="number" class="form-control" id="sortOrder" min="1" value="10" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-success">新增跑馬燈</button>
|
||||||
|
<a href="marquee_ads_list.html" class="btn btn-secondary ms-2">取消</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("adForm").addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("name", document.getElementById("name").value);
|
||||||
|
formData.append("marqueeContent", document.getElementById("marqueeContent").value);
|
||||||
|
formData.append("startDate", document.getElementById("startDate").value);
|
||||||
|
formData.append("endDate", document.getElementById("endDate").value);
|
||||||
|
formData.append("status", document.getElementById("status").value);
|
||||||
|
formData.append("sortOrder", document.getElementById("sortOrder").value);
|
||||||
|
|
||||||
|
console.log("新增的跑馬燈廣告資料:");
|
||||||
|
for (let [key, value] of formData.entries()) {
|
||||||
|
console.log(key + ": ", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
alert("跑馬燈廣告已新增(實際需串接 API 儲存資料)");
|
||||||
|
window.location.href = "marquee_ads_list.html";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
69
Backstage/marquee_ads_edit.html
Normal file
69
Backstage/marquee_ads_edit.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>編輯跑馬燈廣告</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h2 class="mb-4">編輯跑馬燈廣告</h2>
|
||||||
|
<form id="editForm">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">識別名稱 (方便管理)</label>
|
||||||
|
<input type="text" class="form-control" id="name" value="系統維護公告" placeholder="例如:夏季促銷活動">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="marqueeContent" class="form-label">跑馬燈內容</label>
|
||||||
|
<textarea class="form-control" id="marqueeContent" rows="3" required>本網站將於下週三凌晨 02:00 至 04:00 進行系統維護。</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="startDate" class="form-label">開始日期</label>
|
||||||
|
<input type="date" class="form-control" id="startDate" value="2025-05-25" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="endDate" class="form-label">結束日期</label>
|
||||||
|
<input type="date" class="form-control" id="endDate" value="2025-05-28" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="status" class="form-label">狀態</label>
|
||||||
|
<select class="form-select" id="status" required>
|
||||||
|
<option value="">請選擇</option>
|
||||||
|
<option value="啟用">啟用</option>
|
||||||
|
<option value="停用" selected>停用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="sortOrder" class="form-label">排序</label>
|
||||||
|
<input type="number" class="form-control" id="sortOrder" value="2" min="1" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">儲存修改</button>
|
||||||
|
<a href="marquee_ads_list.html" class="btn btn-secondary ms-2">取消</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("editForm").addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("name", document.getElementById("name").value);
|
||||||
|
formData.append("marqueeContent", document.getElementById("marqueeContent").value);
|
||||||
|
formData.append("startDate", document.getElementById("startDate").value);
|
||||||
|
formData.append("endDate", document.getElementById("endDate").value);
|
||||||
|
formData.append("status", document.getElementById("status").value);
|
||||||
|
formData.append("sortOrder", document.getElementById("sortOrder").value);
|
||||||
|
|
||||||
|
console.log("修改後的跑馬燈廣告資料:");
|
||||||
|
for (let [key, value] of formData.entries()) {
|
||||||
|
console.log(key + ": ", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
alert("跑馬燈廣告資料已儲存(實際需串接 API)");
|
||||||
|
window.location.href = "marquee_ads_list.html";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
161
Backstage/marquee_ads_list.html
Normal file
161
Backstage/marquee_ads_list.html
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>跑馬燈廣告列表</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
.status-badge {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.4em 0.7em;
|
||||||
|
}
|
||||||
|
.content-snippet {
|
||||||
|
max-width: 300px; /* Adjusted width slightly */
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.sort-input {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h2>跑馬燈廣告列表</h2>
|
||||||
|
<a href="marquee_ads_add.html" class="btn btn-success">+ 新增跑馬燈</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-2 mb-3 align-items-end">
|
||||||
|
<div class="col-sm-6 col-md-4 col-lg-3">
|
||||||
|
<input type="text" id="searchName" class="form-control" placeholder="搜尋識別名稱或內容" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-2 col-lg-2">
|
||||||
|
<button class="btn btn-outline-primary w-100 rounded-pill" onclick="window.alert('依據查詢關鍵字列出跑馬燈廣告');">搜尋</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 mt-2 d-flex justify-content-between align-items-center flex-wrap">
|
||||||
|
<div class="d-flex gap-2 mb-2">
|
||||||
|
<button class="btn btn-danger" onclick="deleteSelected()">刪除選取</button>
|
||||||
|
<button class="btn btn-primary" onclick="saveSortChanges()">儲存排序變更</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="min-width: 200px;">
|
||||||
|
<select id="sortOrder" class="form-select" onchange="sortTable()">
|
||||||
|
<option value="asc">依排序:由小到大</option>
|
||||||
|
<option value="desc">依排序:由大到小</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="adTable" class="table table-bordered table-hover align-middle">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th><input type="checkbox" onclick="toggleAll(this)" /></th>
|
||||||
|
<th>識別名稱</th>
|
||||||
|
<th>跑馬燈內容</th>
|
||||||
|
<th>期間</th>
|
||||||
|
<th>狀態</th>
|
||||||
|
<th>排序</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" /></td>
|
||||||
|
<td>春季特賣會</td>
|
||||||
|
<td class="content-snippet">全店商品下殺五折起,滿千再送百元折價券!</td>
|
||||||
|
<td>2025/06/01 - 2025/06/30(過期)</td>
|
||||||
|
<td><span class="badge bg-success status-badge">啟用</span></td>
|
||||||
|
<td><input type="number" class="form-control form-control-sm sort-input" value="1" /></td>
|
||||||
|
<td>
|
||||||
|
<a href="marquee_ads_edit.html?id=1" class="btn btn-outline-secondary btn-sm">編輯</a>
|
||||||
|
<button class="btn btn-outline-danger btn-sm" onclick="if(confirm('確定要刪除這則跑馬燈廣告嗎?')) this.closest('tr').remove();">刪除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" /></td>
|
||||||
|
<td>系統維護公告</td>
|
||||||
|
<td class="content-snippet">本網站將於下週三凌晨 02:00 至 04:00 進行系統維護。</td>
|
||||||
|
<td>2023/05/25 - 2025/05/28(未到)</td>
|
||||||
|
<td><span class="badge bg-secondary status-badge">停用</span></td>
|
||||||
|
<td><input type="number" class="form-control form-control-sm sort-input" value="2" /></td>
|
||||||
|
<td>
|
||||||
|
<a href="marquee_ads_edit.html?id=2" class="btn btn-outline-secondary btn-sm">編輯</a>
|
||||||
|
<button class="btn btn-outline-danger btn-sm" onclick="if(confirm('確定要刪除這則跑馬燈廣告嗎?')) this.closest('tr').remove();">刪除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" /></td>
|
||||||
|
<td>系統維護公告</td>
|
||||||
|
<td class="content-snippet">本網站將於下週三凌晨 02:00 至 04:00 進行系統維護。</td>
|
||||||
|
<td>2023/05/25 - 2025/05/28(顯示中)</td>
|
||||||
|
<td><span class="badge bg-secondary status-badge">停用</span></td>
|
||||||
|
<td><input type="number" class="form-control form-control-sm sort-input" value="3" /></td>
|
||||||
|
<td>
|
||||||
|
<a href="marquee_ads_edit.html?id=2" class="btn btn-outline-secondary btn-sm">編輯</a>
|
||||||
|
<button class="btn btn-outline-danger btn-sm" onclick="if(confirm('確定要刪除這則跑馬燈廣告嗎?')) this.closest('tr').remove();">刪除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>第 <span>1</span> 頁,共 <span>1</span> 頁</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary me-1">上一頁</button>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary">下一頁</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
function toggleAll(source) {
|
||||||
|
const checkboxes = document.querySelectorAll('.row-checkbox');
|
||||||
|
checkboxes.forEach(cb => (cb.checked = source.checked));
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteSelected() {
|
||||||
|
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
|
||||||
|
if (checkboxes.length === 0) {
|
||||||
|
alert('請先勾選要刪除的跑馬燈廣告');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!confirm(`確定要刪除 ${checkboxes.length} 則跑馬燈廣告嗎?`)) return;
|
||||||
|
checkboxes.forEach(cb => cb.closest('tr').remove());
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveSortChanges() {
|
||||||
|
const rows = document.querySelectorAll('#adTable tbody tr');
|
||||||
|
rows.forEach(row => {
|
||||||
|
// '識別名稱' is the second child (index 1)
|
||||||
|
const adName = row.children[1].textContent.trim();
|
||||||
|
const newSort = row.querySelector('.sort-input').value;
|
||||||
|
console.log(`跑馬燈廣告:「${adName}」新排序:${newSort}`);
|
||||||
|
// 可在此加上 fetch/ajax 傳到後端
|
||||||
|
});
|
||||||
|
alert('排序變更已儲存(模擬)');
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortTable() {
|
||||||
|
const order = document.getElementById('sortOrder').value;
|
||||||
|
const table = document.getElementById('adTable');
|
||||||
|
const tbody = table.querySelector('tbody');
|
||||||
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||||
|
|
||||||
|
rows.sort((a, b) => {
|
||||||
|
const aValue = parseInt(a.querySelector('.sort-input').value);
|
||||||
|
const bValue = parseInt(b.querySelector('.sort-input').value);
|
||||||
|
return order === 'asc' ? aValue - bValue : bValue - aValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
rows.forEach(row => tbody.appendChild(row));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -4,10 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>居民對話訊息</title>
|
<title>居民對話訊息</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
/>
|
|
||||||
<style>
|
<style>
|
||||||
.chat-box {
|
.chat-box {
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
@ -29,7 +26,7 @@
|
|||||||
margin: 0.25rem 0;
|
margin: 0.25rem 0;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
max-width: 75%;
|
max-width: 75%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.resident-msg {
|
.resident-msg {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
@ -41,19 +38,14 @@
|
|||||||
}
|
}
|
||||||
.canned-replies button {
|
.canned-replies button {
|
||||||
margin: 0.25rem 0.25rem 0 0;
|
margin: 0.25rem 0.25rem 0 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
#messageInput {
|
#messageInput {
|
||||||
|
|
||||||
height: calc(2.25rem + 0.5rem);
|
height: calc(2.25rem + 0.5rem);
|
||||||
}
|
}
|
||||||
#sendBtn {
|
#sendBtn {
|
||||||
|
|
||||||
padding: 0.35rem 1rem;
|
padding: 0.35rem 1rem;
|
||||||
}
|
}
|
||||||
/* 上傳按鈕樣式 */
|
|
||||||
.btn-upload {
|
.btn-upload {
|
||||||
|
|
||||||
padding: 0 0.75rem;
|
padding: 0 0.75rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -68,102 +60,109 @@
|
|||||||
.btn-upload:hover {
|
.btn-upload:hover {
|
||||||
background-color: #e7f1ff;
|
background-color: #e7f1ff;
|
||||||
}
|
}
|
||||||
/* 檔名顯示 */
|
|
||||||
.file-name {
|
.file-name {
|
||||||
margin-top: 0.3rem;
|
margin-top: 0.3rem;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: #555;
|
color: #555;
|
||||||
|
|
||||||
min-height: 1.2rem;
|
min-height: 1.2rem;
|
||||||
}
|
}
|
||||||
/* 調整輸入組合整體圓角 */
|
.input-group > .btn-upload {
|
||||||
.input-group>.btn-upload {
|
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
.input-group>.form-control {
|
.input-group > .form-control {
|
||||||
border-radius: 0 0.375rem 0.375rem 0;
|
border-radius: 0 0.375rem 0.375rem 0;
|
||||||
}
|
}
|
||||||
|
.msg-time {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #888;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
.date-divider {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #555;
|
||||||
|
margin: 1rem 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
<div
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
class="d-flex justify-content-between align-items-center mb-3"
|
|
||||||
>
|
|
||||||
<h4 id="residentName">王小明</h4>
|
<h4 id="residentName">王小明</h4>
|
||||||
<a href="message_list.html" class="btn btn-outline-secondary"
|
<a href="message_list.html" class="btn btn-outline-secondary">← 返回列表</a>
|
||||||
>← 返回列表</a
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chat-box mb-3" id="chatBox">
|
<div class="chat-box mb-3" id="chatBox">
|
||||||
|
<div class="date-divider" id="todayDateDivider"></div>
|
||||||
|
|
||||||
<div class="message-left">
|
<div class="message-left">
|
||||||
<div class="message resident-msg">你好,今天有包裹嗎?</div>
|
<div class="message resident-msg">
|
||||||
|
你好,今天有包裹嗎?
|
||||||
|
<span class="msg-time">09:00</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-right">
|
<div class="message-right">
|
||||||
<div class="message admin-msg">您好,有一個郵件已放置櫃台。</div>
|
<div class="message admin-msg">
|
||||||
|
您好,有一個郵件已放置櫃台。
|
||||||
|
<span class="msg-time">09:02</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-left">
|
<div class="message-left">
|
||||||
<div class="message resident-msg">好的,謝謝您。</div>
|
<div class="message resident-msg">
|
||||||
|
好的,謝謝您。
|
||||||
|
<span class="msg-time">09:03</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-right">
|
<div class="message-right">
|
||||||
<div class="message admin-msg">不客氣,祝您愉快!</div>
|
<div class="message admin-msg">
|
||||||
|
不客氣,祝您愉快!
|
||||||
|
<span class="msg-time">09:04</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 罐頭訊息選單 -->
|
<!-- 快速罐頭訊息 -->
|
||||||
<div class="canned-replies mb-2">
|
<div class="canned-replies mb-2">
|
||||||
<small class="text-muted">快速訊息:</small><br />
|
<small class="text-muted">快速訊息:</small><br />
|
||||||
<button class="btn btn-sm btn-outline-primary">
|
<button class="btn btn-sm btn-outline-primary">您好,請問有什麼需要協助的?</button>
|
||||||
您好,請問有什麼需要協助的?
|
<button class="btn btn-sm btn-outline-primary">已為您處理,請稍候查看。</button>
|
||||||
</button>
|
<button class="btn btn-sm btn-outline-primary">明天早上會有維修人員前來。</button>
|
||||||
<button class="btn btn-sm btn-outline-primary">
|
<button class="btn btn-sm btn-outline-primary">若有其他問題,歡迎再聯繫我們。</button>
|
||||||
已為您處理,請稍候查看。
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-sm btn-outline-primary">
|
|
||||||
明天早上會有維修人員前來。
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-sm btn-outline-primary">
|
|
||||||
若有其他問題,歡迎再聯繫我們。
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 輸入區:上傳按鈕 + 輸入框 + 送出按鈕 -->
|
<!-- 訊息輸入區 -->
|
||||||
<div class="input-group mb-1">
|
<div class="input-group mb-1">
|
||||||
<label for="fileUpload" class="btn-upload" title="上傳照片附件">📷</label>
|
<label for="fileUpload" class="btn-upload" title="上傳照片附件">📷</label>
|
||||||
<input
|
<input type="file" id="fileUpload" accept="image/*" style="display: none" />
|
||||||
type="file"
|
<input type="text" class="form-control" placeholder="輸入訊息..." id="messageInput" />
|
||||||
id="fileUpload"
|
<button class="btn btn-primary" type="button" id="sendBtn">送出</button>
|
||||||
accept="image/*"
|
|
||||||
style="display: none"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="輸入訊息..."
|
|
||||||
id="messageInput"
|
|
||||||
/>
|
|
||||||
<button class="btn btn-primary" type="button" id="sendBtn">
|
|
||||||
送出
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 顯示已選檔案名稱 -->
|
|
||||||
<div id="fileName" class="file-name"></div>
|
<div id="fileName" class="file-name"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// 點擊罐頭訊息時自動填入輸入框
|
// 設定今天日期標籤
|
||||||
|
const today = new Date();
|
||||||
|
const todayStr = today.toLocaleDateString("zh-Hant", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
day: "numeric",
|
||||||
|
weekday: "long"
|
||||||
|
});
|
||||||
|
document.getElementById("todayDateDivider").textContent = "今天 - " + todayStr;
|
||||||
|
|
||||||
|
// 點選快速訊息填入輸入框
|
||||||
document.querySelectorAll(".canned-replies button").forEach((btn) => {
|
document.querySelectorAll(".canned-replies button").forEach((btn) => {
|
||||||
btn.addEventListener("click", () => {
|
btn.addEventListener("click", () => {
|
||||||
document.getElementById("messageInput").value = btn.textContent;
|
document.getElementById("messageInput").value = btn.textContent;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 顯示已選檔案名稱
|
// 顯示上傳檔案名稱
|
||||||
const fileInput = document.getElementById("fileUpload");
|
const fileInput = document.getElementById("fileUpload");
|
||||||
const fileNameDisplay = document.getElementById("fileName");
|
const fileNameDisplay = document.getElementById("fileName");
|
||||||
|
|
||||||
fileInput.addEventListener("change", () => {
|
fileInput.addEventListener("change", () => {
|
||||||
if (fileInput.files.length > 0) {
|
if (fileInput.files.length > 0) {
|
||||||
fileNameDisplay.textContent = "已選擇檔案: " + fileInput.files[0].name;
|
fileNameDisplay.textContent = "已選擇檔案: " + fileInput.files[0].name;
|
||||||
@ -172,17 +171,43 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 模擬送出訊息功能
|
// 模擬送出訊息
|
||||||
document.getElementById("sendBtn").addEventListener("click", () => {
|
document.getElementById("sendBtn").addEventListener("click", () => {
|
||||||
const msg = document.getElementById("messageInput").value.trim();
|
const msg = document.getElementById("messageInput").value.trim();
|
||||||
if (msg) {
|
const fileName = fileInput.files.length > 0 ? fileInput.files[0].name : "";
|
||||||
alert("(模擬送出)訊息內容: " + msg);
|
if (!msg && !fileName) {
|
||||||
document.getElementById("messageInput").value = "";
|
|
||||||
fileInput.value = "";
|
|
||||||
fileNameDisplay.textContent = "";
|
|
||||||
} else {
|
|
||||||
alert("請輸入訊息或上傳圖片!");
|
alert("請輸入訊息或上傳圖片!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const chatBox = document.getElementById("chatBox");
|
||||||
|
|
||||||
|
// 建立訊息元素
|
||||||
|
const msgContainer = document.createElement("div");
|
||||||
|
msgContainer.className = "message-right";
|
||||||
|
|
||||||
|
const msgBubble = document.createElement("div");
|
||||||
|
msgBubble.className = "message admin-msg";
|
||||||
|
msgBubble.innerHTML = `${msg ? msg : ""}${fileName ? "<br><em>📎 " + fileName + "</em>" : ""}`;
|
||||||
|
|
||||||
|
const timeSpan = document.createElement("span");
|
||||||
|
timeSpan.className = "msg-time";
|
||||||
|
const now = new Date();
|
||||||
|
const hour = now.getHours().toString().padStart(2, "0");
|
||||||
|
const minute = now.getMinutes().toString().padStart(2, "0");
|
||||||
|
timeSpan.textContent = `${hour}:${minute}`;
|
||||||
|
|
||||||
|
msgBubble.appendChild(timeSpan);
|
||||||
|
msgContainer.appendChild(msgBubble);
|
||||||
|
chatBox.appendChild(msgContainer);
|
||||||
|
|
||||||
|
// 清空輸入
|
||||||
|
document.getElementById("messageInput").value = "";
|
||||||
|
fileInput.value = "";
|
||||||
|
fileNameDisplay.textContent = "";
|
||||||
|
|
||||||
|
// 自動捲到最底
|
||||||
|
chatBox.scrollTop = chatBox.scrollHeight;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<style>
|
<style>
|
||||||
/* 只針對狀態欄位中的 badge 進行字體放大 */
|
/* 只針對狀態欄位中的 badge 進行字體放大 */
|
||||||
.status-badge {
|
.status-badge {
|
||||||
font-size: 1rem;
|
font-size: 0.9rem;
|
||||||
padding: 0.6em 0.9em;
|
padding: 0.6em 0.9em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -6,166 +6,188 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
body { display: flex; flex-direction: column; min-height: 100vh; margin: 0; }
|
body {
|
||||||
.container.mt-4 { flex-grow: 1; padding-bottom: 70px; }
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.container.mt-4 {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-bottom: 70px;
|
||||||
|
}
|
||||||
nav.pagination-fixed {
|
nav.pagination-fixed {
|
||||||
position: fixed; left: 0; bottom: 0; width: 100%;
|
position: fixed;
|
||||||
background-color: #f8f9fa; padding: 10px 0; border-top: 1px solid #dee2e6; z-index: 1000;
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
nav.pagination-fixed .pagination { margin-bottom: 0; }
|
nav.pagination-fixed .pagination {
|
||||||
.btn {
|
margin-bottom: 0;
|
||||||
font-weight: 500; font-size: 1rem;
|
|
||||||
padding: 0.5rem 0.75rem; transition: all 0.2s ease-in-out;
|
|
||||||
}
|
}
|
||||||
.btn:hover { transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,0.1); }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
<h2 class="mb-4">報修廠商</h2>
|
<h2 class="mb-4">報修廠商</h2>
|
||||||
<div class="row g-2 mb-3">
|
|
||||||
<div class="col-4 col-md-2 col-lg-1">
|
|
||||||
<a href="repair_firm_add.html" class="btn btn-outline-success w-100 rounded-pill">新增</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-4 col-md-2 col-lg-1">
|
|
||||||
<a href="repair_firm_import.html" class="btn btn-outline-info w-100 rounded-pill">匯入</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-4 col-md-2 col-lg-1">
|
|
||||||
<button class="btn btn-outline-secondary w-100 rounded-pill" onclick="exportVendors()">匯出</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-2 mb-3">
|
<div class="row g-2 mb-3">
|
||||||
<div class="col-sm-6 col-md-3 col-lg-2">
|
<div class="col-4 col-md-2 col-lg-1">
|
||||||
<input type="text" id="searchName" class="form-control" placeholder="搜尋廠商名稱">
|
<a href="repair_firm_add.html" class="btn btn-outline-success w-100 rounded-pill btn-sm">新增</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 col-md-4 col-lg-3">
|
<div class="col-4 col-md-2 col-lg-1">
|
||||||
<input type="text" id="searchAddress" class="form-control" placeholder="搜尋地址">
|
<a href="repair_firm_import.html" class="btn btn-outline-info w-100 rounded-pill btn-sm">匯入</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-md-2 col-lg-2">
|
<div class="col-4 col-md-2 col-lg-1">
|
||||||
<button class="btn btn-outline-primary w-100 rounded-pill" onclick="search()">搜尋</button>
|
<button class="btn btn-outline-secondary w-100 rounded-pill btn-sm" onclick="exportVendors()">匯出</button>
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-2 col-lg-1">
|
|
||||||
<button class="btn btn-outline-danger w-100 rounded-pill" onclick="deleteSelected()">刪除勾選</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<thead class="table-dark">
|
|
||||||
<tr>
|
|
||||||
<th><input type="checkbox" id="selectAll" onclick="toggleAll(this)"></th>
|
|
||||||
<th>編號</th>
|
|
||||||
<th>廠商名稱</th>
|
|
||||||
<th>聯絡人</th>
|
|
||||||
<th>聯絡電話</th>
|
|
||||||
<th>地址</th>
|
|
||||||
<th>服務項目</th>
|
|
||||||
<th>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="vendorTable"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="pagination-fixed">
|
<div class="row g-2 mb-3">
|
||||||
<ul class="pagination justify-content-center" id="pagination"></ul>
|
<div class="col-sm-6 col-md-3 col-lg-2">
|
||||||
</nav>
|
<input type="text" id="searchName" class="form-control" placeholder="搜尋廠商名稱">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-4 col-lg-3">
|
||||||
|
<input type="text" id="searchAddress" class="form-control" placeholder="搜尋地址">
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-2 col-lg-2">
|
||||||
|
<button class="btn btn-outline-primary w-100 rounded-pill btn-sm" onclick="search()">搜尋</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-2 col-lg-1">
|
||||||
|
<button class="btn btn-outline-danger w-100 rounded-pill btn-sm" onclick="deleteSelected()">刪除勾選</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<table class="table table-bordered table-hover align-middle">
|
||||||
const pageSize = 10;
|
<thead class="table-dark">
|
||||||
let currentPage = 1;
|
<tr>
|
||||||
|
<th><input type="checkbox" id="selectAll" onclick="toggleAll(this)"></th>
|
||||||
|
<th>編號</th>
|
||||||
|
<th>廠商名稱</th>
|
||||||
|
<th>聯絡人</th>
|
||||||
|
<th>聯絡電話</th>
|
||||||
|
<th>地址</th>
|
||||||
|
<th>服務項目</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="vendorTable"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
let vendors = [
|
<nav class="pagination-fixed">
|
||||||
{ id: 1, name: "好修電器", contact: "陳先生", phone: "0912-111-222", address: "台北市大安區仁愛路一段1號", service: "家電維修" },
|
<ul class="pagination justify-content-center" id="pagination"></ul>
|
||||||
{ id: 2, name: "強力水電", contact: "林小姐", phone: "0988-333-444", address: "新北市板橋區文化路二段88號", service: "水電工程" },
|
</nav>
|
||||||
{ id: 3, name: "快速冷氣", contact: "張先生", phone: "0922-555-666", address: "桃園市中壢區中正路100號", service: "冷氣維修" },
|
|
||||||
{ id: 4, name: "安全消防", contact: "李經理", phone: "0966-777-888", address: "台中市西屯區市政北七路22號", service: "消防設備" }
|
|
||||||
];
|
|
||||||
|
|
||||||
function renderTable(data) {
|
<script>
|
||||||
const tbody = document.getElementById("vendorTable");
|
const pageSize = 5;
|
||||||
tbody.innerHTML = "";
|
let currentPage = 1;
|
||||||
const start = (currentPage - 1) * pageSize;
|
|
||||||
const pageData = data.slice(start, start + pageSize);
|
|
||||||
|
|
||||||
pageData.forEach(v => {
|
let vendors = [
|
||||||
const row = document.createElement("tr");
|
{ id: 1, name: "好修電器", contact: "陳先生", phone: "0912-111-222", address: "台北市大安區仁愛路一段1號", service: "家電維修" },
|
||||||
row.innerHTML = `
|
{ id: 2, name: "強力水電", contact: "林小姐", phone: "0988-333-444", address: "新北市板橋區文化路二段88號", service: "水電工程" },
|
||||||
<td><input type="checkbox" class="row-checkbox" data-id="${v.id}"></td>
|
{ id: 3, name: "快速冷氣", contact: "張先生", phone: "0922-555-666", address: "桃園市中壢區中正路100號", service: "冷氣維修" },
|
||||||
<td>${v.id}</td>
|
{ id: 4, name: "安全消防", contact: "李經理", phone: "0966-777-888", address: "台中市西屯區市政北七路22號", service: "消防設備" }
|
||||||
<td>${v.name}</td>
|
];
|
||||||
<td>${v.contact}</td>
|
|
||||||
<td>${v.phone}</td>
|
|
||||||
<td>${v.address || '-'}</td>
|
|
||||||
<td>${v.service || '-'}</td>
|
|
||||||
<td>
|
|
||||||
<a href="repair_firm_edit.html?id=${v.id}" class="btn btn-warning btn-sm me-1 rounded-pill">編輯</a>
|
|
||||||
<button class="btn btn-outline-danger btn-sm rounded-pill" onclick="deleteVendor(${v.id})">刪除</button>
|
|
||||||
</td>
|
|
||||||
`;
|
|
||||||
tbody.appendChild(row);
|
|
||||||
});
|
|
||||||
|
|
||||||
renderPagination(data.length);
|
function renderTable(data) {
|
||||||
|
const tbody = document.getElementById("vendorTable");
|
||||||
|
tbody.innerHTML = "";
|
||||||
|
const start = (currentPage - 1) * pageSize;
|
||||||
|
const pageData = data.slice(start, start + pageSize);
|
||||||
|
|
||||||
|
pageData.forEach(v => {
|
||||||
|
const row = document.createElement("tr");
|
||||||
|
row.innerHTML = `
|
||||||
|
<td><input type="checkbox" class="row-checkbox" data-id="${v.id}"></td>
|
||||||
|
<td>${v.id}</td>
|
||||||
|
<td>${v.name}</td>
|
||||||
|
<td>${v.contact}</td>
|
||||||
|
<td>${v.phone}</td>
|
||||||
|
<td>${v.address || '-'}</td>
|
||||||
|
<td>${v.service || '-'}</td>
|
||||||
|
<td>
|
||||||
|
<a href="repair_firm_edit.html?id=${v.id}" class="btn btn-outline-secondary btn-sm">編輯</a>
|
||||||
|
<button class="btn btn-outline-danger btn-sm" onclick="deleteVendor(${v.id})">刪除</button>
|
||||||
|
</td>
|
||||||
|
`;
|
||||||
|
tbody.appendChild(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
renderPagination(data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination(totalItems) {
|
||||||
|
const totalPages = Math.ceil(totalItems / pageSize);
|
||||||
|
const pagination = document.getElementById("pagination");
|
||||||
|
pagination.innerHTML = "";
|
||||||
|
|
||||||
|
for (let i = 1; i <= totalPages; i++) {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.className = "page-item" + (i === currentPage ? " active" : "");
|
||||||
|
li.innerHTML = `<a class="page-link" href="#" onclick="goToPage(${i})">${i}</a>`;
|
||||||
|
pagination.appendChild(li);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderPagination(totalItems) {
|
function goToPage(page) {
|
||||||
const totalPages = Math.ceil(totalItems / pageSize);
|
currentPage = page;
|
||||||
const pagination = document.getElementById("pagination");
|
search();
|
||||||
pagination.innerHTML = "";
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= totalPages; i++) {
|
function search() {
|
||||||
const li = document.createElement("li");
|
const nameInput = document.getElementById("searchName").value.toLowerCase();
|
||||||
li.className = "page-item" + (i === currentPage ? " active" : "");
|
const addressInput = document.getElementById("searchAddress").value.toLowerCase();
|
||||||
li.innerHTML = `<a class="page-link" href="#" onclick="goToPage(${i})">${i}</a>`;
|
|
||||||
pagination.appendChild(li);
|
const filtered = vendors.filter(v =>
|
||||||
}
|
v.name.toLowerCase().includes(nameInput) &&
|
||||||
|
(v.address ? v.address.toLowerCase().includes(addressInput) : true)
|
||||||
|
);
|
||||||
|
|
||||||
|
renderTable(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAll(source) {
|
||||||
|
const checkboxes = document.querySelectorAll(".row-checkbox");
|
||||||
|
checkboxes.forEach(cb => cb.checked = source.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteSelected() {
|
||||||
|
if (!confirm("確定要刪除勾選的資料嗎?")) return;
|
||||||
|
const selected = document.querySelectorAll(".row-checkbox:checked");
|
||||||
|
if (selected.length === 0) {
|
||||||
|
alert("請先勾選要刪除的資料");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id));
|
||||||
|
vendors = vendors.filter(v => !idsToDelete.includes(v.id));
|
||||||
|
currentPage = 1;
|
||||||
|
search();
|
||||||
|
document.getElementById("selectAll").checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
function goToPage(page) {
|
function deleteVendor(id) {
|
||||||
currentPage = page;
|
if (!confirm("確定要刪除此筆資料嗎?")) return;
|
||||||
search();
|
vendors = vendors.filter(v => v.id !== id);
|
||||||
window.scrollTo(0, 0);
|
const totalPages = Math.ceil(vendors.length / pageSize);
|
||||||
}
|
if (currentPage > totalPages && totalPages > 0) {
|
||||||
|
currentPage = totalPages;
|
||||||
function search() {
|
} else if (vendors.length === 0) {
|
||||||
const nameInput = document.getElementById("searchName").value.toLowerCase();
|
|
||||||
const addressInput = document.getElementById("searchAddress").value.toLowerCase();
|
|
||||||
|
|
||||||
const filtered = vendors.filter(v =>
|
|
||||||
v.name.toLowerCase().includes(nameInput) &&
|
|
||||||
v.address.toLowerCase().includes(addressInput)
|
|
||||||
);
|
|
||||||
|
|
||||||
renderTable(filtered);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleAll(source) {
|
|
||||||
const checkboxes = document.querySelectorAll(".row-checkbox");
|
|
||||||
checkboxes.forEach(cb => cb.checked = source.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteSelected() {
|
|
||||||
if (!confirm("確定要刪除勾選的資料嗎?")) return;
|
|
||||||
const selected = document.querySelectorAll(".row-checkbox:checked");
|
|
||||||
const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id));
|
|
||||||
vendors = vendors.filter(v => !idsToDelete.includes(v.id));
|
|
||||||
currentPage = 1;
|
currentPage = 1;
|
||||||
search();
|
|
||||||
document.getElementById("selectAll").checked = false;
|
|
||||||
}
|
}
|
||||||
|
search();
|
||||||
|
}
|
||||||
|
|
||||||
function deleteVendor(id) {
|
function exportVendors() {
|
||||||
if (!confirm("確定要刪除此筆資料嗎?")) return;
|
alert("匯出搜尋結果(若無搜尋條件則匯出全部)");
|
||||||
vendors = vendors.filter(v => v.id !== id);
|
}
|
||||||
search();
|
|
||||||
}
|
|
||||||
|
|
||||||
function exportVendors() {
|
search(); // 初始載入
|
||||||
alert("匯出搜尋結果(若無搜尋條件則匯出全部)");
|
</script>
|
||||||
}
|
|
||||||
|
|
||||||
search(); // 初始載入
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
.container.mt-4 {
|
.container.mt-4 {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding-bottom: 70px;
|
/* padding-bottom: 70px; Removed as pagination is no longer fixed */
|
||||||
}
|
}
|
||||||
|
|
||||||
#qrcodeModal .modal-body {
|
#qrcodeModal .modal-body {
|
||||||
@ -24,32 +24,27 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.pagination-fixed {
|
/* Removed nav.pagination-fixed styles */
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
/* Custom styles ONLY for buttons that are .btn but NOT .btn-sm or .btn-lg */
|
||||||
bottom: 0;
|
/* This ensures .btn-sm (like pagination and table action buttons) use Bootstrap's default styling */
|
||||||
width: 100%;
|
.btn:not(.btn-sm):not(.btn-lg) {
|
||||||
background-color: #f8f9fa;
|
font-weight: 500; /* Custom font-weight for standard-sized buttons */
|
||||||
padding: 10px 0;
|
font-size: 1rem; /* Custom font-size for standard-sized buttons */
|
||||||
border-top: 1px solid #dee2e6;
|
padding: 0.5rem 0.75rem; /* Custom padding for standard-sized buttons */
|
||||||
z-index: 1000;
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.pagination-fixed .pagination {
|
/* Custom hover effect ONLY for buttons that are .btn but NOT .btn-sm or .btn-lg */
|
||||||
margin-bottom: 0;
|
.btn:not(.btn-sm):not(.btn-lg):hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
/* Ensure all buttons, including btn-sm, can have rounded-pill if specified by class */
|
||||||
|
.rounded-pill {
|
||||||
|
border-radius: 50rem !important; /* Ensure pill shape if class is present */
|
||||||
}
|
}
|
||||||
|
|
||||||
button.btn {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1rem;
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn:hover {
|
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -73,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead class="table-dark">
|
<thead class="table-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th><input type="checkbox" id="selectAll" onclick="toggleAll(this)"></th>
|
<th><input type="checkbox" id="selectAll" onclick="toggleAll(this)"></th>
|
||||||
@ -87,13 +82,15 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody id="residentTable"></tbody>
|
<tbody id="residentTable"></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="pagination-fixed">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<ul class="pagination justify-content-center" id="pagination"></ul>
|
<div>第 <span id="currentPageDisplay">1</span> 頁,共 <span id="totalPagesDisplay">1</span> 頁</div>
|
||||||
</nav>
|
<div>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary me-1" id="prevBtn">上一頁</button>
|
||||||
<div class="modal fade" id="qrcodeModal" tabindex="-1" aria-labelledby="qrcodeModalLabel" aria-hidden="true">
|
<button class="btn btn-sm btn-outline-secondary" id="nextBtn">下一頁</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> <div class="modal fade" id="qrcodeModal" tabindex="-1" aria-labelledby="qrcodeModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-sm modal-dialog-centered">
|
<div class="modal-dialog modal-sm modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@ -111,8 +108,10 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const pageSize = 10;
|
const pageSize = 5;
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
|
let currentFilteredData = []; // To store the currently filtered data
|
||||||
|
|
||||||
let residents = [
|
let residents = [
|
||||||
{ id: 1, name: "王小明", email: "xiaoming@example.com", phone: "0912-345-678", room: "A101" },
|
{ id: 1, name: "王小明", email: "xiaoming@example.com", phone: "0912-345-678", room: "A101" },
|
||||||
{ id: 2, name: "林美麗", email: "meili@example.com", phone: "0987-654-321", room: "A102" },
|
{ id: 2, name: "林美麗", email: "meili@example.com", phone: "0987-654-321", room: "A102" },
|
||||||
@ -128,15 +127,16 @@
|
|||||||
{ id: 12, name: "鄧紫棋", email: "gem@example.com", phone: "0944-444-444", room: "F602" }
|
{ id: 12, name: "鄧紫棋", email: "gem@example.com", phone: "0944-444-444", room: "F602" }
|
||||||
];
|
];
|
||||||
|
|
||||||
function renderTable(data) {
|
function renderTable() { // Removed 'data' parameter, uses currentFilteredData
|
||||||
const tbody = document.getElementById("residentTable");
|
const tbody = document.getElementById("residentTable");
|
||||||
tbody.innerHTML = "";
|
tbody.innerHTML = "";
|
||||||
|
|
||||||
const start = (currentPage - 1) * pageSize;
|
const start = (currentPage - 1) * pageSize;
|
||||||
const pageData = data.slice(start, start + pageSize);
|
const pageData = currentFilteredData.slice(start, start + pageSize);
|
||||||
|
|
||||||
pageData.forEach(r => {
|
pageData.forEach(r => {
|
||||||
const row = document.createElement("tr");
|
const row = document.createElement("tr");
|
||||||
|
// The "開通" button is .btn-sm, will use Bootstrap default small styling
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
<td><input type="checkbox" class="row-checkbox" data-id="${r.id}"></td>
|
<td><input type="checkbox" class="row-checkbox" data-id="${r.id}"></td>
|
||||||
<td>${r.id}</td>
|
<td>${r.id}</td>
|
||||||
@ -149,40 +149,58 @@
|
|||||||
tbody.appendChild(row);
|
tbody.appendChild(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
renderPagination(data.length);
|
// Update pagination display
|
||||||
}
|
const totalItems = currentFilteredData.length;
|
||||||
|
|
||||||
function renderPagination(totalItems) {
|
|
||||||
const totalPages = Math.ceil(totalItems / pageSize);
|
const totalPages = Math.ceil(totalItems / pageSize);
|
||||||
const pagination = document.getElementById("pagination");
|
document.getElementById("currentPageDisplay").textContent = currentPage;
|
||||||
pagination.innerHTML = "";
|
document.getElementById("totalPagesDisplay").textContent = totalPages > 0 ? totalPages : 1;
|
||||||
|
|
||||||
for (let i = 1; i <= totalPages; i++) {
|
document.getElementById("prevBtn").disabled = currentPage === 1;
|
||||||
const li = document.createElement("li");
|
document.getElementById("nextBtn").disabled = currentPage === totalPages || totalPages === 0;
|
||||||
li.className = "page-item" + (i === currentPage ? " active" : "");
|
|
||||||
li.innerHTML = `<a class="page-link" href="#" onclick="goToPage(${i})">${i}</a>`;
|
|
||||||
pagination.appendChild(li);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToPage(page) {
|
// Removed old renderPagination function
|
||||||
currentPage = page;
|
|
||||||
search();
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function search() {
|
function applyFiltersAndRender() {
|
||||||
const nameInput = document.getElementById("searchName").value.toLowerCase();
|
const nameInput = document.getElementById("searchName").value.toLowerCase();
|
||||||
const emailInput = document.getElementById("searchEmail").value.toLowerCase();
|
const emailInput = document.getElementById("searchEmail").value.toLowerCase();
|
||||||
const roomInput = document.getElementById("searchRoom").value.toLowerCase();
|
const roomInput = document.getElementById("searchRoom").value.toLowerCase();
|
||||||
|
|
||||||
const filtered = residents.filter(r =>
|
currentFilteredData = residents.filter(r =>
|
||||||
r.name.toLowerCase().includes(nameInput) &&
|
r.name.toLowerCase().includes(nameInput) &&
|
||||||
r.email.toLowerCase().includes(emailInput) &&
|
r.email.toLowerCase().includes(emailInput) &&
|
||||||
r.room.toLowerCase().includes(roomInput)
|
r.room.toLowerCase().includes(roomInput)
|
||||||
);
|
);
|
||||||
|
|
||||||
renderTable(filtered);
|
const totalPages = Math.ceil(currentFilteredData.length / pageSize);
|
||||||
|
if (currentPage > totalPages && totalPages > 0) {
|
||||||
|
currentPage = totalPages;
|
||||||
|
} else if (totalPages === 0) {
|
||||||
|
currentPage = 1;
|
||||||
|
}
|
||||||
|
renderTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("prevBtn").addEventListener("click", () => {
|
||||||
|
if (currentPage > 1) {
|
||||||
|
currentPage--;
|
||||||
|
renderTable();
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("nextBtn").addEventListener("click", () => {
|
||||||
|
const totalPages = Math.ceil(currentFilteredData.length / pageSize);
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
currentPage++;
|
||||||
|
renderTable();
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function search() {
|
||||||
|
currentPage = 1; // Reset to page 1 for new search
|
||||||
|
applyFiltersAndRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAll(source) {
|
function toggleAll(source) {
|
||||||
@ -197,21 +215,23 @@
|
|||||||
const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id));
|
const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id));
|
||||||
|
|
||||||
residents = residents.filter(r => !idsToDelete.includes(r.id));
|
residents = residents.filter(r => !idsToDelete.includes(r.id));
|
||||||
currentPage = 1;
|
// currentFilteredData will be updated by applyFiltersAndRender
|
||||||
search();
|
// currentPage will be adjusted if necessary by applyFiltersAndRender
|
||||||
|
applyFiltersAndRender();
|
||||||
document.getElementById("selectAll").checked = false;
|
document.getElementById("selectAll").checked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showQRCode(url) {
|
function showQRCode(url) {
|
||||||
const qrContainer = document.getElementById("qrcode");
|
const qrContainer = document.getElementById("qrcode");
|
||||||
qrContainer.innerHTML = "";
|
qrContainer.innerHTML = ""; // Clear previous QR code
|
||||||
new QRCode(qrContainer, {
|
new QRCode(qrContainer, {
|
||||||
text: url,
|
text: url,
|
||||||
width: 200,
|
width: 200, // Ensure QR code is reasonably sized
|
||||||
height: 200
|
height: 200
|
||||||
});
|
});
|
||||||
|
|
||||||
const modal = new bootstrap.Modal(document.getElementById("qrcodeModal"));
|
const modalElement = document.getElementById("qrcodeModal");
|
||||||
|
const modal = bootstrap.Modal.getInstance(modalElement) || new bootstrap.Modal(modalElement);
|
||||||
modal.show();
|
modal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +239,8 @@
|
|||||||
alert("這裡可以接掃描裝置或開啟相機功能");
|
alert("這裡可以接掃描裝置或開啟相機功能");
|
||||||
}
|
}
|
||||||
|
|
||||||
search(); // 初次載入
|
// Initial load
|
||||||
|
search();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -7,17 +7,29 @@
|
|||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
body { display: flex; flex-direction: column; min-height: 100vh; margin: 0; }
|
body { display: flex; flex-direction: column; min-height: 100vh; margin: 0; }
|
||||||
.container.mt-4 { flex-grow: 1; padding-bottom: 70px; }
|
.container.mt-4 { flex-grow: 1; }
|
||||||
nav.pagination-fixed {
|
|
||||||
position: fixed; left: 0; bottom: 0; width: 100%;
|
/* Custom styles ONLY for buttons that are .btn but NOT .btn-sm or .btn-lg */
|
||||||
background-color: #f8f9fa; padding: 10px 0; border-top: 1px solid #dee2e6; z-index: 1000;
|
/* This ensures .btn-sm (like pagination and table action buttons) use Bootstrap's default styling */
|
||||||
|
.btn:not(.btn-sm):not(.btn-lg) {
|
||||||
|
font-weight: 500; /* Custom font-weight for standard-sized buttons */
|
||||||
|
font-size: 1rem; /* Custom font-size for standard-sized buttons */
|
||||||
|
padding: 0.5rem 0.75rem; /* Custom padding for standard-sized buttons */
|
||||||
|
/* The transition below is more general than Bootstrap's default, apply specifically if needed */
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
nav.pagination-fixed .pagination { margin-bottom: 0; }
|
|
||||||
.btn {
|
/* Custom hover effect ONLY for buttons that are .btn but NOT .btn-sm or .btn-lg */
|
||||||
font-weight: 500; font-size: 1rem;
|
.btn:not(.btn-sm):not(.btn-lg):hover {
|
||||||
padding: 0.5rem 0.75rem; transition: all 0.2s ease-in-out;
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
.btn:hover { transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,0.1); }
|
|
||||||
|
/* Default Bootstrap .btn already includes transitions.
|
||||||
|
If you had other general .btn styles that should apply to ALL buttons (including .btn-sm)
|
||||||
|
and are compatible with notice_list.html's appearance, they could go here.
|
||||||
|
For "exactly the same" pagination buttons, it's safer to let Bootstrap handle .btn-sm styling.
|
||||||
|
*/
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -50,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead class="table-dark">
|
<thead class="table-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th><input type="checkbox" id="selectAll" onclick="toggleAll(this)"></th>
|
<th><input type="checkbox" id="selectAll" onclick="toggleAll(this)"></th>
|
||||||
@ -64,15 +76,19 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody id="residentTable"></tbody>
|
<tbody id="residentTable"></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="pagination-fixed">
|
|
||||||
<ul class="pagination justify-content-center" id="pagination"></ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>第 <span id="currentPageDisplay">1</span> 頁,共 <span id="totalPagesDisplay">1</span> 頁</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary me-1" id="prevBtn">上一頁</button>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary" id="nextBtn">下一頁</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const pageSize = 10;
|
const pageSize = 5;
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
|
let currentFilteredData = []; // To store the currently filtered data
|
||||||
|
|
||||||
let residents = [
|
let residents = [
|
||||||
{ id: 1, name: "王小明", email: "xiaoming@example.com", phone: "0912-345-678", room: "A101" },
|
{ id: 1, name: "王小明", email: "xiaoming@example.com", phone: "0912-345-678", room: "A101" },
|
||||||
@ -89,14 +105,15 @@
|
|||||||
{ id: 12, name: "鄧紫棋", email: "gem@example.com", phone: "0944-444-444", room: "A202" }
|
{ id: 12, name: "鄧紫棋", email: "gem@example.com", phone: "0944-444-444", room: "A202" }
|
||||||
];
|
];
|
||||||
|
|
||||||
function renderTable(data) {
|
function renderTable() {
|
||||||
const tbody = document.getElementById("residentTable");
|
const tbody = document.getElementById("residentTable");
|
||||||
tbody.innerHTML = "";
|
tbody.innerHTML = "";
|
||||||
const start = (currentPage - 1) * pageSize;
|
const start = (currentPage - 1) * pageSize;
|
||||||
const pageData = data.slice(start, start + pageSize);
|
const pageData = currentFilteredData.slice(start, start + pageSize);
|
||||||
|
|
||||||
pageData.forEach(r => {
|
pageData.forEach(r => {
|
||||||
const row = document.createElement("tr");
|
const row = document.createElement("tr");
|
||||||
|
// Table action buttons are also .btn-sm and will use Bootstrap defaults
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
<td><input type="checkbox" class="row-checkbox" data-id="${r.id}"></td>
|
<td><input type="checkbox" class="row-checkbox" data-id="${r.id}"></td>
|
||||||
<td>${r.id}</td>
|
<td>${r.id}</td>
|
||||||
@ -112,38 +129,54 @@
|
|||||||
tbody.appendChild(row);
|
tbody.appendChild(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
renderPagination(data.length);
|
const totalItems = currentFilteredData.length;
|
||||||
}
|
|
||||||
|
|
||||||
function renderPagination(totalItems) {
|
|
||||||
const totalPages = Math.ceil(totalItems / pageSize);
|
const totalPages = Math.ceil(totalItems / pageSize);
|
||||||
const pagination = document.getElementById("pagination");
|
document.getElementById("currentPageDisplay").textContent = currentPage;
|
||||||
pagination.innerHTML = "";
|
document.getElementById("totalPagesDisplay").textContent = totalPages > 0 ? totalPages : 1;
|
||||||
|
|
||||||
for (let i = 1; i <= totalPages; i++) {
|
document.getElementById("prevBtn").disabled = currentPage === 1;
|
||||||
const li = document.createElement("li");
|
document.getElementById("nextBtn").disabled = currentPage === totalPages || totalPages === 0;
|
||||||
li.className = "page-item" + (i === currentPage ? " active" : "");
|
}
|
||||||
li.innerHTML = `<a class="page-link" href="#" onclick="goToPage(${i})">${i}</a>`;
|
|
||||||
pagination.appendChild(li);
|
function applyFiltersAndRender() {
|
||||||
|
const nameInput = document.getElementById("searchName").value.toLowerCase();
|
||||||
|
const emailInput = document.getElementById("searchEmail").value.toLowerCase();
|
||||||
|
|
||||||
|
currentFilteredData = residents.filter(r =>
|
||||||
|
r.name.toLowerCase().includes(nameInput) &&
|
||||||
|
r.email.toLowerCase().includes(emailInput)
|
||||||
|
);
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(currentFilteredData.length / pageSize);
|
||||||
|
if (currentPage > totalPages && totalPages > 0) {
|
||||||
|
currentPage = totalPages;
|
||||||
|
} else if (totalPages === 0) {
|
||||||
|
currentPage = 1;
|
||||||
|
}
|
||||||
|
renderTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById("prevBtn").addEventListener("click", () => {
|
||||||
|
if (currentPage > 1) {
|
||||||
|
currentPage--;
|
||||||
|
renderTable();
|
||||||
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
function goToPage(page) {
|
document.getElementById("nextBtn").addEventListener("click", () => {
|
||||||
currentPage = page;
|
const totalPages = Math.ceil(currentFilteredData.length / pageSize);
|
||||||
search();
|
if (currentPage < totalPages) {
|
||||||
window.scrollTo(0, 0);
|
currentPage++;
|
||||||
}
|
renderTable();
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function search() {
|
function search() {
|
||||||
const nameInput = document.getElementById("searchName").value.toLowerCase();
|
currentPage = 1;
|
||||||
const emailInput = document.getElementById("searchEmail").value.toLowerCase();
|
applyFiltersAndRender();
|
||||||
|
|
||||||
const filtered = residents.filter(r =>
|
|
||||||
r.name.toLowerCase().includes(nameInput) &&
|
|
||||||
r.email.toLowerCase().includes(emailInput)
|
|
||||||
);
|
|
||||||
|
|
||||||
renderTable(filtered);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAll(source) {
|
function toggleAll(source) {
|
||||||
@ -156,22 +189,26 @@
|
|||||||
const selected = document.querySelectorAll(".row-checkbox:checked");
|
const selected = document.querySelectorAll(".row-checkbox:checked");
|
||||||
const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id));
|
const idsToDelete = Array.from(selected).map(cb => parseInt(cb.dataset.id));
|
||||||
residents = residents.filter(r => !idsToDelete.includes(r.id));
|
residents = residents.filter(r => !idsToDelete.includes(r.id));
|
||||||
currentPage = 1;
|
applyFiltersAndRender();
|
||||||
search();
|
|
||||||
document.getElementById("selectAll").checked = false;
|
document.getElementById("selectAll").checked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteResident(id) {
|
function deleteResident(id) {
|
||||||
if (!confirm("確定要刪除此筆資料嗎?")) return;
|
if (!confirm("確定要刪除此筆資料嗎?")) return;
|
||||||
residents = residents.filter(r => r.id !== id);
|
residents = residents.filter(r => r.id !== id);
|
||||||
search();
|
applyFiltersAndRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportResidents() {
|
function exportResidents() {
|
||||||
alert("直接匯出搜尋查出的結果,如果沒有搜尋就全部匯出");
|
alert("直接匯出搜尋查出的結果,如果沒有搜尋就全部匯出");
|
||||||
|
if (currentFilteredData.length === 0) {
|
||||||
|
console.log("Exporting all residents:", residents);
|
||||||
|
} else {
|
||||||
|
console.log("Exporting filtered residents:", currentFilteredData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
search(); // 初始化載入
|
search();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -57,22 +57,30 @@
|
|||||||
color: #007bff;
|
color: #007bff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-submenu > .submenu-toggle {
|
.has-submenu > .submenu-toggle,
|
||||||
|
.li-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-submenu > .submenu-toggle > span:first-child {
|
.submenu-toggle > span:first-child,
|
||||||
|
.li-content > span:first-child {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
white-space: nowrap;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.parent-badge {
|
.parent-badge,
|
||||||
|
.badge {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
min-width: 20px;
|
min-width: 20px;
|
||||||
|
height: 20px;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -80,7 +88,12 @@
|
|||||||
background-color: red;
|
background-color: red;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
white-space: nowrap;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parent-badge {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,42 +125,6 @@
|
|||||||
.has-submenu ul li:hover {
|
.has-submenu ul li:hover {
|
||||||
background-color: #deeaf6;
|
background-color: #deeaf6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 20px;
|
|
||||||
padding: 2px 6px;
|
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: white;
|
|
||||||
background-color: red;
|
|
||||||
border-radius: 10px;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar ul li .li-content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 讓 "未開通居民" 等文字完整顯示 ---- */
|
|
||||||
.sidebar ul li .li-content > span:first-child {
|
|
||||||
flex-grow: 1;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar ul li .li-content span {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -172,6 +149,7 @@
|
|||||||
<li onclick="requestNavigation('resident_list.html', this)">居民列表</li>
|
<li onclick="requestNavigation('resident_list.html', this)">居民列表</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="has-submenu">
|
<li class="has-submenu">
|
||||||
<div class="submenu-toggle" onclick="toggleSubmenu(this)">
|
<div class="submenu-toggle" onclick="toggleSubmenu(this)">
|
||||||
<span>警急通報</span>
|
<span>警急通報</span>
|
||||||
@ -196,19 +174,22 @@
|
|||||||
<span class="submenu-arrow">▼</span>
|
<span class="submenu-arrow">▼</span>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li onclick="requestNavigation('CCCCC.html', this)">首頁輪播廣告</li>
|
<li onclick="requestNavigation('carousel_ads_list.html', this)">首頁輪播廣告</li>
|
||||||
<li onclick="requestNavigation('CCCCC.html', this)">跑馬登廣告</li>
|
<li onclick="requestNavigation('marquee_ads_list.html', this)">跑馬登廣告</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li onclick="requestNavigation('some_page1.html', this)">出入管理</li>
|
<li onclick="requestNavigation('some_page1.html', this)">出入管理</li>
|
||||||
|
|
||||||
<li onclick="requestNavigation('message_list.html', this)">
|
<li onclick="requestNavigation('message_list.html', this)">
|
||||||
<div class="li-content">
|
<div class="li-content">
|
||||||
<span>訊息通知</span>
|
<span>訊息通知</span>
|
||||||
<span class="badge" data-count="99">99</span>
|
<span class="badge" data-count="99">99</span>
|
||||||
|
<span class="submenu-arrow"> </span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="has-submenu">
|
|
||||||
|
<li class="has-submenu">
|
||||||
<div class="submenu-toggle" onclick="toggleSubmenu(this)">
|
<div class="submenu-toggle" onclick="toggleSubmenu(this)">
|
||||||
<span>水電報修</span>
|
<span>水電報修</span>
|
||||||
<span class="parent-badge"></span>
|
<span class="parent-badge"></span>
|
||||||
@ -216,41 +197,46 @@
|
|||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li onclick="requestNavigation('repair-list.html', this)">
|
<li onclick="requestNavigation('repair-list.html', this)">
|
||||||
<div class="li-content">
|
<div class="li-content">
|
||||||
<span>報修申請</span>
|
<span>報修申請</span>
|
||||||
<span class="badge" data-count="99">99</span>
|
<span class="badge" data-count="99">99</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li onclick="requestNavigation('repair_firm_list.html', this)">報修廠商</li>
|
<li onclick="requestNavigation('repair_firm_list.html', this)">報修廠商</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li onclick="requestNavigation('feedback_list.html', this)">
|
||||||
|
<div class="li-content">
|
||||||
|
<span>意見回饋</span>
|
||||||
|
<span class="badge" data-count="99">99</span>
|
||||||
|
<span class="submenu-arrow"> </span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li onclick="requestNavigation('some_page6.html', this)">報表匯出</li>
|
<li onclick="requestNavigation('some_page6.html', this)">報表匯出</li>
|
||||||
<li onclick="requestNavigation('some_page7.html', this)">設定</li>
|
<li onclick="requestNavigation('some_page7.html', this)">設定</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function requestNavigation(url, clickedElement) {
|
function requestNavigation(url, clickedElement) {
|
||||||
console.log('Sidebar: 發送導航請求 ->', url);
|
console.log('Sidebar: 發送導航請求 ->', url);
|
||||||
parent.postMessage({ type: 'navigate', url: url }, '*');
|
parent.postMessage({ type: 'navigate', url: url }, '*');
|
||||||
|
|
||||||
// 移除所有主項目和子項目的 active class
|
|
||||||
const allItems = document.querySelectorAll('.sidebar ul li, .sidebar ul ul li');
|
const allItems = document.querySelectorAll('.sidebar ul li, .sidebar ul ul li');
|
||||||
allItems.forEach(item => item.classList.remove('active'));
|
allItems.forEach(item => item.classList.remove('active'));
|
||||||
|
|
||||||
// 為當前點擊的項目添加 active class
|
|
||||||
clickedElement.classList.add('active');
|
clickedElement.classList.add('active');
|
||||||
|
|
||||||
// 處理父層active標示(僅當點擊子選單時)
|
|
||||||
if (clickedElement.closest('.has-submenu ul')) {
|
if (clickedElement.closest('.has-submenu ul')) {
|
||||||
const parentLi = clickedElement.closest('.has-submenu');
|
const parentLi = clickedElement.closest('.has-submenu');
|
||||||
if (parentLi) {
|
if (parentLi) {
|
||||||
// 移除所有頂層 active,改由父層設定 active
|
|
||||||
document.querySelectorAll('.sidebar > ul > li').forEach(li => li.classList.remove('active'));
|
document.querySelectorAll('.sidebar > ul > li').forEach(li => li.classList.remove('active'));
|
||||||
parentLi.classList.add('active');
|
parentLi.classList.add('active');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 點擊頂層 li
|
|
||||||
document.querySelectorAll('.sidebar > ul > li').forEach(li => li.classList.remove('active'));
|
document.querySelectorAll('.sidebar > ul > li').forEach(li => li.classList.remove('active'));
|
||||||
clickedElement.classList.add('active');
|
clickedElement.classList.add('active');
|
||||||
}
|
}
|
||||||
@ -274,21 +260,18 @@
|
|||||||
submenuParents.forEach(parent => {
|
submenuParents.forEach(parent => {
|
||||||
const isOpen = parent.classList.contains('open');
|
const isOpen = parent.classList.contains('open');
|
||||||
const badgeContainer = parent.querySelector('.parent-badge');
|
const badgeContainer = parent.querySelector('.parent-badge');
|
||||||
|
|
||||||
const subBadges = parent.querySelectorAll('ul .badge');
|
const subBadges = parent.querySelectorAll('ul .badge');
|
||||||
let total = 0;
|
|
||||||
|
|
||||||
|
let total = 0;
|
||||||
subBadges.forEach(badge => {
|
subBadges.forEach(badge => {
|
||||||
const raw = badge.getAttribute('data-count');
|
const raw = badge.getAttribute('data-count');
|
||||||
const val = parseInt(raw, 10);
|
const val = parseInt(raw, 10);
|
||||||
if (!isNaN(val)) {
|
if (!isNaN(val)) total += val;
|
||||||
total += val;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isOpen && total > 0) {
|
if (!isOpen && total > 0) {
|
||||||
badgeContainer.textContent = total;
|
badgeContainer.textContent = total;
|
||||||
badgeContainer.style.display = 'inline-block';
|
badgeContainer.style.display = 'inline-flex';
|
||||||
} else {
|
} else {
|
||||||
badgeContainer.style.display = 'none';
|
badgeContainer.style.display = 'none';
|
||||||
badgeContainer.textContent = '';
|
badgeContainer.textContent = '';
|
||||||
@ -296,7 +279,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
updateParentBadges();
|
updateParentBadges();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user