Spaces:
Running
Running
Upload 2 files
Browse files- admin.html +50 -0
- admin.js +140 -10
admin.html
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
<!DOCTYPE html>
|
| 3 |
+
<html lang="th">
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8">
|
| 6 |
+
<title>Admin เช็กบิลโต๊ะ</title>
|
| 7 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 8 |
+
<style>
|
| 9 |
+
body { font-family: 'Sarabun', sans-serif; background: #f9f5ef; margin:0; padding:20px;}
|
| 10 |
+
.box { max-width:440px; margin:30px auto; background:#fff; border-radius:10px; box-shadow:0 0 8px #b3c6e0; padding:22px; }
|
| 11 |
+
h2 { color:#145bb4; }
|
| 12 |
+
.order-item {display:flex;justify-content:space-between;align-items:center;margin-bottom:5px;}
|
| 13 |
+
.total {font-weight:bold; text-align:right; color:#1566a4; margin-top:14px;}
|
| 14 |
+
button {padding:6px 16px;border:none;border-radius:8px;background:#145bb4;color:#fff;font-weight:bold;font-size:1rem;margin:0 2px;}
|
| 15 |
+
select,input[type=number] {font-size:1rem; margin:0 3px;}
|
| 16 |
+
#add-form { margin:20px 0; padding:10px 0; border-top:1px solid #eee; }
|
| 17 |
+
.order-item button {background:#e64343;}
|
| 18 |
+
.order-item button:hover {background:#b21818;}
|
| 19 |
+
#add-btn {background:#1780ec;}
|
| 20 |
+
</style>
|
| 21 |
+
</head>
|
| 22 |
+
<body>
|
| 23 |
+
<div class="box">
|
| 24 |
+
<h2>เช็กบิลโต๊ะ</h2>
|
| 25 |
+
<label>เลือกโต๊ะ:
|
| 26 |
+
<select id="table">
|
| 27 |
+
<option value="1">1</option>
|
| 28 |
+
<option value="2">2</option>
|
| 29 |
+
<option value="3">3</option>
|
| 30 |
+
<option value="4">4</option>
|
| 31 |
+
<option value="5">5</option>
|
| 32 |
+
</select>
|
| 33 |
+
<button onclick="loadOrder()" id="fetch-btn" style="background:#2362aa;">ดึงข้อมูล</button>
|
| 34 |
+
</label>
|
| 35 |
+
<div id="order-list" style="margin-top:18px;"></div>
|
| 36 |
+
<div id="total" class="total"></div>
|
| 37 |
+
<button id="checkout-btn" onclick="checkout()" style="display:none;background:#2362aa;">เช็กบิล</button>
|
| 38 |
+
|
| 39 |
+
<div id="add-form">
|
| 40 |
+
<h3>เพิ่มรายการ</h3>
|
| 41 |
+
<select id="add-menu">
|
| 42 |
+
<option value="">เลือกเมนู</option>
|
| 43 |
+
</select>
|
| 44 |
+
<input type="number" id="add-qty" value="1" min="1" style="width:45px;">
|
| 45 |
+
<button id="add-btn" onclick="addOrder()">เพิ่มรายการ</button>
|
| 46 |
+
</div>
|
| 47 |
+
</div>
|
| 48 |
+
<script src="admin.js"></script>
|
| 49 |
+
</body>
|
| 50 |
+
</html>
|
admin.js
CHANGED
|
@@ -1,17 +1,90 @@
|
|
|
|
|
| 1 |
const scriptURL = "https://api.sheetbest.com/sheets/67a68e64-dca9-4eea-99b7-0431c5786cf6";
|
| 2 |
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
async function loadOrder() {
|
| 5 |
const table = document.getElementById("table").value;
|
| 6 |
const res = await fetch(`${scriptURL}?table=${table}`);
|
| 7 |
const data = await res.json();
|
| 8 |
-
|
| 9 |
-
// filter เฉพาะเลขโต๊ะตรงเป๊ะ (กันปัญหาโต๊ะอื่นหลุดมา)
|
| 10 |
-
const orders = data.filter(
|
| 11 |
-
i =>
|
| 12 |
-
(i.status ?? "") !== "paid" &&
|
| 13 |
-
String(i.table).trim() === String(table)
|
| 14 |
-
);
|
| 15 |
|
| 16 |
let html = "";
|
| 17 |
let sum = 0;
|
|
@@ -29,7 +102,11 @@ async function loadOrder() {
|
|
| 29 |
document.getElementById("checkout-btn").style.display = "none";
|
| 30 |
} else {
|
| 31 |
for (const [name, item] of Object.entries(summary)) {
|
| 32 |
-
html += `<div class="order-item">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
}
|
| 34 |
document.getElementById("checkout-btn").style.display = "inline-block";
|
| 35 |
}
|
|
@@ -37,9 +114,59 @@ async function loadOrder() {
|
|
| 37 |
document.getElementById("total").textContent = sum ? `รวมทั้งหมด ${sum} ฿` : "";
|
| 38 |
}
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
async function checkout() {
|
| 41 |
const table = document.getElementById("table").value;
|
| 42 |
-
// PATCH ทุก row ของโต๊ะนี้ให้ status=paid
|
| 43 |
await fetch(`${scriptURL}?table=${table}`, {
|
| 44 |
method: "PATCH",
|
| 45 |
headers: { "Content-Type": "application/json" },
|
|
@@ -48,3 +175,6 @@ async function checkout() {
|
|
| 48 |
alert("เช็กบิลเรียบร้อย!");
|
| 49 |
loadOrder();
|
| 50 |
}
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
const scriptURL = "https://api.sheetbest.com/sheets/67a68e64-dca9-4eea-99b7-0431c5786cf6";
|
| 3 |
|
| 4 |
+
const menu = [
|
| 5 |
+
{
|
| 6 |
+
section: "เมนูข้าวต้ม",
|
| 7 |
+
items: [
|
| 8 |
+
{ name: "ข้าวต้มปลา (ปลาช่อน)", price: 59 },
|
| 9 |
+
{ name: "ข้าวต้มปลา (ปลากระพง)", price: 79 },
|
| 10 |
+
{ name: "ข้าวต้มปลาแห้ง (ปลาช่อน)", price: 59 },
|
| 11 |
+
{ name: "ข้าวต้มปลาแห้ง (ปลากระพง)", price: 79 },
|
| 12 |
+
{ name: "ข้าวต้มกุ้ง", price: 79 },
|
| 13 |
+
{ name: "ข้าวต้มปลาหมึก", price: 59 },
|
| 14 |
+
{ name: "ข้าวต้มทะเล", price: 99 }
|
| 15 |
+
]
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
section: "เมนูอาหารไทย",
|
| 19 |
+
items: [
|
| 20 |
+
{ name: "ผัดฉ่าปลา (ปลาช่อน)", price: 69 },
|
| 21 |
+
{ name: "ผัดฉ่าปลา (ปลากระพง)", price: 89 },
|
| 22 |
+
{ name: "ผัดขี้เมาปลา (ปลาช่อน)", price: 69 },
|
| 23 |
+
{ name: "ผัดขี้เมาปลา (ปลากระพง)", price: 89 },
|
| 24 |
+
{ name: "ต้มยำเนื้อปลา (ปลาช่อน)", price: 69 },
|
| 25 |
+
{ name: "ต้มยำเนื้อปลา (ปลากระพง)", price: 89 },
|
| 26 |
+
{ name: "ต้มยำหัวปลา", price: 89 },
|
| 27 |
+
{ name: "ต้มยำทะเล", price: 109 },
|
| 28 |
+
{ name: "ต้มยำกุ้ง", price: 99 },
|
| 29 |
+
{ name: "เกาเหลาปลา (ปลาช่อน)", price: 79 },
|
| 30 |
+
{ name: "เกาเหลาปลา (ปลากระพง)", price: 99 },
|
| 31 |
+
{ name: "เกาเหลาทะเล", price: 109 },
|
| 32 |
+
{ name: "ลวกจิ้มปลา (ปลาช่อน)", price: 79 },
|
| 33 |
+
{ name: "ลวกจิ้มปลา (ปลากระพง)", price: 99 },
|
| 34 |
+
{ name: "รวมทะเลลวกจิ้ม", price: 129 },
|
| 35 |
+
{ name: "ยำรวมทะเล", price: 109 },
|
| 36 |
+
{ name: "ยำแมงกะพรุน", price: 69 },
|
| 37 |
+
{ name: "แมงกะพรุนล้นน้ำมันงา", price: 59 }
|
| 38 |
+
]
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
section: "ของทอด",
|
| 42 |
+
items: [
|
| 43 |
+
{ name: "แหนมกระดูกอ่อนหมู", price: 69 },
|
| 44 |
+
{ name: "ปีกไก่ทอด", price: 79 },
|
| 45 |
+
{ name: "คางกุ้งทอด", price: 59 },
|
| 46 |
+
{ name: "เฟรนซ์ฟรายส์", price: 59 },
|
| 47 |
+
{ name: "ไข่เจียว", price: 20 }
|
| 48 |
+
]
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
section: "เครื่องดื่ม/อื่นๆ",
|
| 52 |
+
items: [
|
| 53 |
+
{ name: "ข้าวสวย", price: 15 },
|
| 54 |
+
{ name: "น้ำเปล่า", price: 15 },
|
| 55 |
+
{ name: "น้ำอัดลม", price: 20 },
|
| 56 |
+
{ name: "น้ำอัดลม ขวดใหญ่", price: 40 },
|
| 57 |
+
{ name: "น้ำแข็ง", price: 25 },
|
| 58 |
+
{ name: "โซดา", price: 20 }
|
| 59 |
+
]
|
| 60 |
+
}
|
| 61 |
+
];
|
| 62 |
+
|
| 63 |
+
// Render dropdown เมนู
|
| 64 |
+
function renderMenuDropdown() {
|
| 65 |
+
const select = document.getElementById("add-menu");
|
| 66 |
+
let html = `<option value="">เลือกเมนู</option>`;
|
| 67 |
+
menu.forEach(section => {
|
| 68 |
+
section.items.forEach(item => {
|
| 69 |
+
html += `<option value="${item.name}">${item.name} (${item.price} ฿)</option>`;
|
| 70 |
+
});
|
| 71 |
+
});
|
| 72 |
+
select.innerHTML = html;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
// Filter เฉพาะเลขโต๊ะตรงเป๊ะและยังไม่เช็กบิล/ไม่ถูกลบ
|
| 76 |
+
function filterOrders(data, table) {
|
| 77 |
+
return data.filter(
|
| 78 |
+
i => (i.status ?? "") !== "paid" && (i.status ?? "") !== "deleted" && String(i.table).trim() === String(table)
|
| 79 |
+
);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
// แสดงออเดอร์
|
| 83 |
async function loadOrder() {
|
| 84 |
const table = document.getElementById("table").value;
|
| 85 |
const res = await fetch(`${scriptURL}?table=${table}`);
|
| 86 |
const data = await res.json();
|
| 87 |
+
const orders = filterOrders(data, table);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
let html = "";
|
| 90 |
let sum = 0;
|
|
|
|
| 102 |
document.getElementById("checkout-btn").style.display = "none";
|
| 103 |
} else {
|
| 104 |
for (const [name, item] of Object.entries(summary)) {
|
| 105 |
+
html += `<div class="order-item">
|
| 106 |
+
<span>${name} x${item.qty}</span>
|
| 107 |
+
<span>${item.price * item.qty} ฿</span>
|
| 108 |
+
<button onclick="removeOrder('${name}')">ลบ</button>
|
| 109 |
+
</div>`;
|
| 110 |
}
|
| 111 |
document.getElementById("checkout-btn").style.display = "inline-block";
|
| 112 |
}
|
|
|
|
| 114 |
document.getElementById("total").textContent = sum ? `รวมทั้งหมด ${sum} ฿` : "";
|
| 115 |
}
|
| 116 |
|
| 117 |
+
// เพิ่มรายการออเดอร์
|
| 118 |
+
async function addOrder() {
|
| 119 |
+
const table = document.getElementById("table").value;
|
| 120 |
+
const menuName = document.getElementById("add-menu").value;
|
| 121 |
+
const qty = parseInt(document.getElementById("add-qty").value, 10) || 1;
|
| 122 |
+
|
| 123 |
+
// หาราคาจากเมนู
|
| 124 |
+
let price = 0;
|
| 125 |
+
menu.forEach(section => {
|
| 126 |
+
section.items.forEach(item => {
|
| 127 |
+
if(item.name === menuName) price = item.price;
|
| 128 |
+
});
|
| 129 |
+
});
|
| 130 |
+
|
| 131 |
+
if (!menuName || !qty) return alert("กรุณาเลือกเมนูและจำนวน");
|
| 132 |
+
|
| 133 |
+
for (let i = 0; i < qty; i++) {
|
| 134 |
+
const order = {
|
| 135 |
+
table: table,
|
| 136 |
+
menu: menuName,
|
| 137 |
+
price: price,
|
| 138 |
+
qty: 1,
|
| 139 |
+
note: "[เพิ่มโดยแอดมิน]",
|
| 140 |
+
timestamp: new Date().toISOString(),
|
| 141 |
+
status: ""
|
| 142 |
+
};
|
| 143 |
+
await fetch(scriptURL, {
|
| 144 |
+
method: "POST",
|
| 145 |
+
headers: { "Content-Type": "application/json" },
|
| 146 |
+
body: JSON.stringify(order),
|
| 147 |
+
});
|
| 148 |
+
}
|
| 149 |
+
alert("เพิ่มรายการสำเร็จ");
|
| 150 |
+
loadOrder();
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
// ลบเมนูทั้งเมนู (ของโต๊ะนี้ ที่ยังไม่เช็กบิล)
|
| 154 |
+
async function removeOrder(menuName) {
|
| 155 |
+
const table = document.getElementById("table").value;
|
| 156 |
+
if (!confirm(`ต้องการลบเมนู "${menuName}" ออกจากโต๊ะ ${table} ?`)) return;
|
| 157 |
+
|
| 158 |
+
await fetch(`${scriptURL}?table=${table}&menu=${encodeURIComponent(menuName)}`, {
|
| 159 |
+
method: "PATCH",
|
| 160 |
+
headers: { "Content-Type": "application/json" },
|
| 161 |
+
body: JSON.stringify({ status: "deleted" }),
|
| 162 |
+
});
|
| 163 |
+
alert("ลบเมนูสำเร็จ");
|
| 164 |
+
loadOrder();
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
// เช็กบิล (mark paid)
|
| 168 |
async function checkout() {
|
| 169 |
const table = document.getElementById("table").value;
|
|
|
|
| 170 |
await fetch(`${scriptURL}?table=${table}`, {
|
| 171 |
method: "PATCH",
|
| 172 |
headers: { "Content-Type": "application/json" },
|
|
|
|
| 175 |
alert("เช็กบิลเรียบร้อย!");
|
| 176 |
loadOrder();
|
| 177 |
}
|
| 178 |
+
|
| 179 |
+
renderMenuDropdown();
|
| 180 |
+
loadOrder();
|