Add 2 files
Browse files- index.html +262 -235
- prompts.txt +7 -1
index.html
CHANGED
|
@@ -3,280 +3,307 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
| 6 |
-
<title>Ứng dụng
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
-
<
|
| 9 |
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
| 10 |
<style>
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
}
|
| 15 |
-
#invoice, #invoice * {
|
| 16 |
-
visibility: visible;
|
| 17 |
-
}
|
| 18 |
-
#invoice {
|
| 19 |
-
position: absolute;
|
| 20 |
-
top: 0;
|
| 21 |
-
left: 0;
|
| 22 |
-
width: 100%;
|
| 23 |
-
padding: 20px;
|
| 24 |
-
font-size: 14px;
|
| 25 |
-
}
|
| 26 |
-
#app, #printBtn, #downloadPdfBtn {
|
| 27 |
-
display: none;
|
| 28 |
-
}
|
| 29 |
}
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
text-align: center;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
}
|
| 36 |
</style>
|
| 37 |
</head>
|
| 38 |
-
<body class="bg-gray-100 text-gray-800 font-sans">
|
| 39 |
|
| 40 |
-
<
|
| 41 |
-
|
| 42 |
-
<
|
|
|
|
| 43 |
|
| 44 |
-
|
| 45 |
-
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
| 46 |
-
<input id="customerName" type="text" placeholder="Tên khách hàng" class="border p-2 rounded">
|
| 47 |
-
<input id="customerAddress" type="text" placeholder="Địa chỉ" class="border p-2 rounded">
|
| 48 |
-
<input id="customerPhone" type="text" placeholder="Số điện thoại" class="border p-2 rounded">
|
| 49 |
-
</div>
|
| 50 |
|
| 51 |
-
<!--
|
| 52 |
-
<div class="
|
| 53 |
-
<
|
| 54 |
-
<
|
| 55 |
-
<input id="productName" type="text" placeholder="Tên sản phẩm" class="border p-2 rounded">
|
| 56 |
-
<input id="price" type="number" placeholder="Đơn giá" class="border p-2 rounded text-right" oninput="calculateTotal()">
|
| 57 |
-
<input id="quantity" type="number" placeholder="Số lượng" class="border p-2 rounded text-center" oninput="calculateTotal()">
|
| 58 |
-
<input id="discount" type="number" placeholder="Chiết khấu (%)" class="border p-2 rounded text-center" oninput="calculateTotal()">
|
| 59 |
</div>
|
| 60 |
|
| 61 |
-
<
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
| 66 |
-
<div>
|
| 67 |
-
<label class="block mb-2 font-semibold">Thành tiền:</label>
|
| 68 |
-
<input id="totalInput" type="text" class="border p-2 rounded w-full text-right font-bold" readonly>
|
| 69 |
</div>
|
| 70 |
-
<button onclick="addToInvoice()" class="bg-green-500 text-white px-4 py-3 rounded hover:bg-green-600 transition">
|
| 71 |
-
➕ Thêm vào hóa đơn
|
| 72 |
-
</button>
|
| 73 |
-
</div>
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
<
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
<th class="border border-gray-300 px-4 py-2">Mã SP</th>
|
| 82 |
-
<th class="border border-gray-300 px-4 py-2">Tên SP</th>
|
| 83 |
-
<th class="border border-gray-300 px-4 py-2">SL</th>
|
| 84 |
-
<th class="border border-gray-300 px-4 py-2">Đơn giá</th>
|
| 85 |
-
<th class="border border-gray-300 px-4 py-2">Chiết khấu (%)</th>
|
| 86 |
-
<th class="border border-gray-300 px-4 py-2">Thành tiền</th>
|
| 87 |
-
</tr>
|
| 88 |
-
</thead>
|
| 89 |
-
<tbody id="invoiceTableBody">
|
| 90 |
-
<!-- Sản phẩm sẽ được thêm ở đây -->
|
| 91 |
-
</tbody>
|
| 92 |
-
</table>
|
| 93 |
-
</div>
|
| 94 |
-
|
| 95 |
-
<!-- Nút hành động -->
|
| 96 |
-
<div class="flex justify-center gap-4 mt-6">
|
| 97 |
-
<button onclick="window.print()" id="printBtn" class="bg-blue-500 text-white px-6 py-2 rounded hover:bg-blue-600 transition">
|
| 98 |
-
🖨️ In Hóa Đơn
|
| 99 |
-
</button>
|
| 100 |
-
<button onclick="downloadPDF()" id="downloadPdfBtn" class="bg-purple-500 text-white px-6 py-2 rounded hover:bg-purple-600 transition">
|
| 101 |
-
📄 Xuất PDF
|
| 102 |
-
</button>
|
| 103 |
-
</div>
|
| 104 |
-
</div>
|
| 105 |
-
|
| 106 |
-
<!-- Phần in hóa đơn -->
|
| 107 |
-
<div id="invoice" class="hidden print:block p-6 bg-white max-w-3xl mx-auto">
|
| 108 |
-
<div class="text-center mb-4">
|
| 109 |
-
<img src="https://via.placeholder.com/100x50.png?text=LOGO" alt="Logo công ty" class="mx-auto mb-2">
|
| 110 |
-
<h2 class="text-2xl font-bold">HÓA ĐƠN BÁN HÀNG</h2>
|
| 111 |
-
<p class="text-sm text-gray-500">Ngày: <span id="invoiceDate"></span></p>
|
| 112 |
-
</div>
|
| 113 |
-
|
| 114 |
-
<!-- Thông tin khách hàng -->
|
| 115 |
-
<div class="mb-4">
|
| 116 |
-
<p><strong>Tên khách hàng:</strong> <span id="printCustomerName"></span></p>
|
| 117 |
-
<p><strong>Địa chỉ:</strong> <span id="printCustomerAddress"></span></p>
|
| 118 |
-
<p><strong>Điện thoại:</strong> <span id="printCustomerPhone"></span></p>
|
| 119 |
-
</div>
|
| 120 |
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
<
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
<
|
| 128 |
-
<
|
| 129 |
-
<
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
</tr>
|
| 133 |
-
</thead>
|
| 134 |
-
<tbody id="invoicePrintBody">
|
| 135 |
-
<!-- Dữ liệu sản phẩm sẽ được thêm ở đây -->
|
| 136 |
-
</tbody>
|
| 137 |
-
</table>
|
| 138 |
|
| 139 |
-
|
| 140 |
-
|
|
|
|
|
|
|
|
|
|
| 141 |
</div>
|
| 142 |
|
| 143 |
-
|
| 144 |
-
<p><strong>Ghi chú:</strong> <span id="printNote"></span></p>
|
| 145 |
-
</div>
|
| 146 |
|
| 147 |
-
|
| 148 |
-
|
|
|
|
| 149 |
|
| 150 |
<script>
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
}
|
| 164 |
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
const
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
|
| 173 |
-
|
| 174 |
-
|
|
|
|
|
|
|
| 175 |
return;
|
| 176 |
}
|
| 177 |
|
| 178 |
-
const
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
row.innerHTML = `
|
| 184 |
-
<td class="border border-gray-300 px-4 py-2">${index}</td>
|
| 185 |
-
<td class="border border-gray-300 px-4 py-2">${code}</td>
|
| 186 |
-
<td class="border border-gray-300 px-4 py-2">${name}</td>
|
| 187 |
-
<td class="border border-gray-300 px-4 py-2 text-center">${quantity}</td>
|
| 188 |
-
<td class="border border-gray-300 px-4 py-2 text-right">${price.toLocaleString('vi-VN')}</td>
|
| 189 |
-
<td class="border border-gray-300 px-4 py-2 text-center">${discount}</td>
|
| 190 |
-
<td class="border border-gray-300 px-4 py-2 text-right">${amount.toLocaleString('vi-VN')}</td>
|
| 191 |
-
`;
|
| 192 |
-
document.getElementById('invoiceTableBody').appendChild(row);
|
| 193 |
-
|
| 194 |
-
// Thêm vào phần in
|
| 195 |
-
const printRow = document.createElement('tr');
|
| 196 |
-
printRow.innerHTML = `
|
| 197 |
-
<td class="border border-gray-300 px-4 py-2">${index}</td>
|
| 198 |
-
<td class="border border-gray-300 px-4 py-2">${code}</td>
|
| 199 |
-
<td class="border border-gray-300 px-4 py-2">${name}</td>
|
| 200 |
-
<td class="border border-gray-300 px-4 py-2 text-center">${quantity}</td>
|
| 201 |
-
<td class="border border-gray-300 px-4 py-2 text-right">${price.toLocaleString('vi-VN')}</td>
|
| 202 |
-
<td class="border border-gray-300 px-4 py-2 text-center">${discount}</td>
|
| 203 |
-
<td class="border border-gray-300 px-4 py-2 text-right">${amount.toLocaleString('vi-VN')}</td>
|
| 204 |
-
`;
|
| 205 |
-
document.getElementById('invoicePrintBody').appendChild(printRow);
|
| 206 |
-
|
| 207 |
-
// Cập nhật tổng
|
| 208 |
-
total += amount;
|
| 209 |
-
document.getElementById('totalPrintAmount').textContent = total.toLocaleString('vi-VN') + " VNĐ";
|
| 210 |
-
|
| 211 |
-
// Cập nhật thông tin khách hàng và ghi chú
|
| 212 |
-
document.getElementById('printCustomerName').textContent = document.getElementById('customerName').value;
|
| 213 |
-
document.getElementById('printCustomerAddress').textContent = document.getElementById('customerAddress').value;
|
| 214 |
-
document.getElementById('printCustomerPhone').textContent = document.getElementById('customerPhone').value;
|
| 215 |
-
document.getElementById('printNote').textContent = note;
|
| 216 |
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
|
| 221 |
-
|
| 222 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
|
|
|
| 232 |
}
|
| 233 |
|
| 234 |
-
function
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
tempContainer.style.position = "absolute";
|
| 243 |
-
tempContainer.style.left = "-9999px";
|
| 244 |
-
document.body.appendChild(tempContainer);
|
| 245 |
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
});
|
| 254 |
-
}
|
| 255 |
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
}
|
| 272 |
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
});
|
| 280 |
</script>
|
| 281 |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=bep40/invoice" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 282 |
</html>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
| 6 |
+
<title>Ứng dụng PDF Viewer với Thumbnail & Slideshow</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.min.js"></script>
|
|
|
|
| 9 |
<style>
|
| 10 |
+
.highlight {
|
| 11 |
+
background-color: yellow;
|
| 12 |
+
font-weight: bold;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
}
|
| 14 |
+
.thumbnail {
|
| 15 |
+
position: relative;
|
| 16 |
+
cursor: pointer;
|
| 17 |
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
| 18 |
+
}
|
| 19 |
+
.thumbnail:hover {
|
| 20 |
+
transform: scale(1.05);
|
| 21 |
+
box-shadow: 0 0 12px rgba(0, 0, 0, 0.2);
|
| 22 |
+
}
|
| 23 |
+
.thumbnail img {
|
| 24 |
+
width: 100%;
|
| 25 |
+
height: auto;
|
| 26 |
+
border-radius: 8px;
|
| 27 |
+
}
|
| 28 |
+
.thumbnail .title {
|
| 29 |
+
position: absolute;
|
| 30 |
+
bottom: 0;
|
| 31 |
+
left: 0;
|
| 32 |
+
right: 0;
|
| 33 |
+
background: rgba(0,0,0,0.6);
|
| 34 |
+
color: white;
|
| 35 |
text-align: center;
|
| 36 |
+
padding: 4px 0;
|
| 37 |
+
font-size: 14px;
|
| 38 |
+
border-bottom-left-radius: 8px;
|
| 39 |
+
border-bottom-right-radius: 8px;
|
| 40 |
+
}
|
| 41 |
+
#pdfViewer canvas {
|
| 42 |
+
display: block;
|
| 43 |
+
margin: 0 auto;
|
| 44 |
+
max-width: 100%;
|
| 45 |
+
height: auto;
|
| 46 |
+
border-radius: 8px;
|
| 47 |
+
}
|
| 48 |
+
.text-layer {
|
| 49 |
+
position: absolute;
|
| 50 |
+
top: 0;
|
| 51 |
+
left: 0;
|
| 52 |
+
width: 100%;
|
| 53 |
+
height: 100%;
|
| 54 |
+
pointer-events: none;
|
| 55 |
+
z-index: 10;
|
| 56 |
+
font-size: 16px;
|
| 57 |
+
line-height: 1.5;
|
| 58 |
}
|
| 59 |
</style>
|
| 60 |
</head>
|
| 61 |
+
<body class="bg-gray-100 text-gray-800 font-sans min-h-screen flex flex-col items-center">
|
| 62 |
|
| 63 |
+
<header class="w-full bg-gradient-to-r from-indigo-600 to-purple-700 text-white py-5 shadow-md">
|
| 64 |
+
<h1 class="text-3xl font-bold text-center">Ứng dụng PDF Viewer với Thumbnail & Tìm kiếm</h1>
|
| 65 |
+
<p class="text-center mt-1 text-sm">Xem, trình chiếu và tìm kiếm văn bản trong file PDF</p>
|
| 66 |
+
</header>
|
| 67 |
|
| 68 |
+
<main class="max-w-7xl w-full mx-auto p-6 mt-6 flex flex-col gap-6">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
+
<!-- Danh sách PDF dạng thumbnail -->
|
| 71 |
+
<div class="border border-gray-300 rounded-lg p-4 bg-gray-50">
|
| 72 |
+
<h2 class="text-lg font-semibold mb-3">Chọn tài liệu PDF:</h2>
|
| 73 |
+
<div id="pdfGrid" class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4"></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
</div>
|
| 75 |
|
| 76 |
+
<!-- Khung xem PDF -->
|
| 77 |
+
<div class="flex flex-col items-center">
|
| 78 |
+
<div id="pdfViewer" class="relative border border-gray-300 rounded-lg p-4 bg-gray-100 min-h-96 w-full max-w-4xl">
|
| 79 |
+
<p class="text-center text-gray-400 mt-20">Chọn một file PDF từ danh sách để xem</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
|
| 82 |
+
<!-- Điều hướng trang -->
|
| 83 |
+
<div class="flex justify-between items-center w-full max-w-4xl mt-4">
|
| 84 |
+
<button onclick="prevPage()" id="prevBtn" class="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600 transition disabled:opacity-50 disabled:cursor-not-allowed">⬅️ Trang trước</button>
|
| 85 |
+
<span id="pageInfo" class="text-lg font-semibold">Trang: 1 / 1</span>
|
| 86 |
+
<button onclick="nextPage()" id="nextBtn" class="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600 transition disabled:opacity-50 disabled:cursor-not-allowed">Trang sau ➡️</button>
|
| 87 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
+
<!-- Slideshow controls -->
|
| 90 |
+
<div class="flex gap-4 items-center mt-4">
|
| 91 |
+
<button onclick="startSlideshow()" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition">▶️ Bắt đầu Slideshow</button>
|
| 92 |
+
<button onclick="stopSlideshow()" class="bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600 transition">⏹️ Dừng Slideshow</button>
|
| 93 |
+
<span>Chuyển trang mỗi:</span>
|
| 94 |
+
<select id="intervalSelect" class="border rounded px-3 py-1">
|
| 95 |
+
<option value="2000">2 giây</option>
|
| 96 |
+
<option value="3000" selected>3 giây</option>
|
| 97 |
+
<option value="5000">5 giây</option>
|
| 98 |
+
</select>
|
| 99 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
+
<!-- Tìm kiếm nội dung -->
|
| 102 |
+
<div class="flex gap-2 items-center mt-6 w-full max-w-4xl">
|
| 103 |
+
<input type="text" id="searchText" placeholder="Nhập từ khóa tìm kiếm..." class="border p-2 rounded flex-grow focus:ring-2 focus:ring-blue-400 outline-none">
|
| 104 |
+
<button onclick="searchText()" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 transition">🔍 Tìm kiếm</button>
|
| 105 |
+
</div>
|
| 106 |
</div>
|
| 107 |
|
| 108 |
+
</main>
|
|
|
|
|
|
|
| 109 |
|
| 110 |
+
<footer class="mt-10 text-gray-500 text-center pb-4 text-sm">
|
| 111 |
+
© 2025 - Ứng dụng xem PDF với trang bìa, slideshow và tìm kiếm
|
| 112 |
+
</footer>
|
| 113 |
|
| 114 |
<script>
|
| 115 |
+
const pdfViewer = document.getElementById('pdfViewer');
|
| 116 |
+
const pageInfo = document.getElementById('pageInfo');
|
| 117 |
+
const prevBtn = document.getElementById('prevBtn');
|
| 118 |
+
const nextBtn = document.getElementById('nextBtn');
|
| 119 |
+
const pdfGrid = document.getElementById('pdfGrid');
|
| 120 |
+
const searchTextEl = document.getElementById('searchText');
|
| 121 |
+
const intervalSelect = document.getElementById('intervalSelect');
|
| 122 |
+
|
| 123 |
+
let pdfDocs = [];
|
| 124 |
+
let currentDocIndex = -1;
|
| 125 |
+
let currentPage = 1;
|
| 126 |
+
let totalPages = 0;
|
| 127 |
+
let currentHighlight = '';
|
| 128 |
+
let slideshowInterval = null;
|
| 129 |
+
|
| 130 |
+
// Danh sách file PDF mẫu
|
| 131 |
+
const pdfFiles = [
|
| 132 |
+
{ name: 'Tài liệu 1', url: 'files/document1.pdf', thumb: 'files/thumb1.jpg' },
|
| 133 |
+
{ name: 'Tài liệu 2', url: 'files/document2.pdf', thumb: 'files/thumb2.jpg' },
|
| 134 |
+
{ name: 'Tài liệu 3', url: 'files/document3.pdf', thumb: 'files/thumb3.jpg' },
|
| 135 |
+
{ name: 'Tài liệu 4', url: 'files/document4.pdf', thumb: 'files/thumb4.jpg' },
|
| 136 |
+
{ name: 'Tài liệu 5', url: 'files/document5.pdf', thumb: 'files/thumb5.jpg' }
|
| 137 |
+
];
|
| 138 |
+
|
| 139 |
+
// Tạo thumbnail và danh sách PDF
|
| 140 |
+
function updatePdfGrid() {
|
| 141 |
+
pdfGrid.innerHTML = '';
|
| 142 |
+
pdfFiles.forEach((file, index) => {
|
| 143 |
+
const div = document.createElement('div');
|
| 144 |
+
div.className = 'thumbnail';
|
| 145 |
+
div.innerHTML = `
|
| 146 |
+
<img src="${file.thumb}" alt="${file.name}" class="w-full h-auto object-cover">
|
| 147 |
+
<div class="title">${file.name}</div>
|
| 148 |
+
`;
|
| 149 |
+
div.onclick = () => {
|
| 150 |
+
currentDocIndex = index;
|
| 151 |
+
currentPage = 1;
|
| 152 |
+
currentHighlight = '';
|
| 153 |
+
loadPdf(index);
|
| 154 |
+
};
|
| 155 |
+
pdfGrid.appendChild(div);
|
| 156 |
+
});
|
| 157 |
}
|
| 158 |
|
| 159 |
+
// Load file PDF từ URL
|
| 160 |
+
function loadPdf(index) {
|
| 161 |
+
const file = pdfFiles[index];
|
| 162 |
+
pdfjsLib.getDocument(file.url).promise.then(pdf => {
|
| 163 |
+
pdfDocs[index] = pdf;
|
| 164 |
+
totalPages = pdf.numPages;
|
| 165 |
+
pageInfo.textContent = `Trang: 1 / ${totalPages}`;
|
| 166 |
+
renderPage(currentPage);
|
| 167 |
+
enableNavigationButtons();
|
| 168 |
+
});
|
| 169 |
+
}
|
| 170 |
|
| 171 |
+
// Render trang PDF
|
| 172 |
+
function renderPage(pageNumber) {
|
| 173 |
+
if (currentDocIndex === -1) {
|
| 174 |
+
pdfViewer.innerHTML = '<p class="text-center text-gray-400 mt-20">Vui lòng chọn một file PDF từ danh sách.</p>';
|
| 175 |
return;
|
| 176 |
}
|
| 177 |
|
| 178 |
+
const pdf = pdfDocs[currentDocIndex];
|
| 179 |
+
if (!pdf) {
|
| 180 |
+
pdfViewer.innerHTML = '<p class="text-center text-gray-400 mt-20">Đang tải tài liệu...</p>';
|
| 181 |
+
return;
|
| 182 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
|
| 184 |
+
pdf.getPage(pageNumber).then(page => {
|
| 185 |
+
pdfViewer.innerHTML = '';
|
| 186 |
+
const viewport = page.getViewport({ scale: 1.5 });
|
| 187 |
+
const canvas = document.createElement('canvas');
|
| 188 |
+
const context = canvas.getContext('2d');
|
| 189 |
+
canvas.height = viewport.height;
|
| 190 |
+
canvas.width = viewport.width;
|
| 191 |
+
|
| 192 |
+
const renderContext = {
|
| 193 |
+
canvasContext: context,
|
| 194 |
+
viewport: viewport
|
| 195 |
+
};
|
| 196 |
+
|
| 197 |
+
pdfViewer.appendChild(canvas);
|
| 198 |
+
page.render(renderContext).promise.then(() => {
|
| 199 |
+
if (currentHighlight.trim() !== '') {
|
| 200 |
+
renderTextLayer(page, currentHighlight);
|
| 201 |
+
}
|
| 202 |
+
});
|
| 203 |
+
});
|
| 204 |
+
}
|
| 205 |
|
| 206 |
+
// Vẽ lớp văn bản để highlight
|
| 207 |
+
function renderTextLayer(page, highlightText) {
|
| 208 |
+
const viewport = page.getViewport({ scale: 1.5 });
|
| 209 |
+
const textLayer = document.createElement('div');
|
| 210 |
+
textLayer.className = 'text-layer';
|
| 211 |
+
pdfViewer.appendChild(textLayer);
|
| 212 |
+
|
| 213 |
+
page.getTextContent().then(textContent => {
|
| 214 |
+
textLayer.innerHTML = '';
|
| 215 |
+
textContent.items.forEach(item => {
|
| 216 |
+
const x = item.transform[4];
|
| 217 |
+
const y = viewport.height - item.transform[5];
|
| 218 |
+
const span = document.createElement('span');
|
| 219 |
+
span.style.position = 'absolute';
|
| 220 |
+
span.style.left = `${x}px`;
|
| 221 |
+
span.style.top = `${y}px`;
|
| 222 |
+
span.style.fontSize = `${viewport.scale * 14}px`;
|
| 223 |
+
span.style.pointerEvents = 'auto';
|
| 224 |
+
span.innerHTML = item.str.replace(new RegExp(`(${highlightText})`, 'gi'), '<span class="highlight">$1</span>');
|
| 225 |
+
textLayer.appendChild(span);
|
| 226 |
+
});
|
| 227 |
+
});
|
| 228 |
+
}
|
| 229 |
|
| 230 |
+
// Điều hướng trang
|
| 231 |
+
function nextPage() {
|
| 232 |
+
if (currentDocIndex === -1) return;
|
| 233 |
+
if (currentPage < totalPages) {
|
| 234 |
+
currentPage++;
|
| 235 |
+
pageInfo.textContent = `Trang: ${currentPage} / ${totalPages}`;
|
| 236 |
+
renderPage(currentPage);
|
| 237 |
+
}
|
| 238 |
+
enableNavigationButtons();
|
| 239 |
}
|
| 240 |
|
| 241 |
+
function prevPage() {
|
| 242 |
+
if (currentDocIndex === -1) return;
|
| 243 |
+
if (currentPage > 1) {
|
| 244 |
+
currentPage--;
|
| 245 |
+
pageInfo.textContent = `Trang: ${currentPage} / ${totalPages}`;
|
| 246 |
+
renderPage(currentPage);
|
| 247 |
+
}
|
| 248 |
+
enableNavigationButtons();
|
| 249 |
+
}
|
| 250 |
|
| 251 |
+
function enableNavigationButtons() {
|
| 252 |
+
prevBtn.disabled = currentPage <= 1;
|
| 253 |
+
nextBtn.disabled = currentPage >= totalPages;
|
| 254 |
+
}
|
|
|
|
|
|
|
|
|
|
| 255 |
|
| 256 |
+
// Tìm kiếm văn bản trong PDF
|
| 257 |
+
function searchText() {
|
| 258 |
+
const query = searchTextEl.value.trim();
|
| 259 |
+
if (!query) return alert("Vui lòng nhập từ khóa để tìm kiếm.");
|
| 260 |
+
if (currentDocIndex === -1) return alert("Vui lòng chọn một file PDF từ danh sách.");
|
| 261 |
+
|
| 262 |
+
const pdf = pdfDocs[currentDocIndex];
|
| 263 |
+
let found = false;
|
| 264 |
+
|
| 265 |
+
for (let i = 1; i <= pdf.numPages; i++) {
|
| 266 |
+
pdf.getPage(i).then(page => {
|
| 267 |
+
page.getTextContent().then(textContent => {
|
| 268 |
+
const text = textContent.items.map(item => item.str).join(' ').toLowerCase();
|
| 269 |
+
if (text.includes(query.toLowerCase())) {
|
| 270 |
+
currentPage = i;
|
| 271 |
+
pageInfo.textContent = `Trang: ${currentPage} / ${totalPages}`;
|
| 272 |
+
currentHighlight = query;
|
| 273 |
+
renderPage(currentPage);
|
| 274 |
+
found = true;
|
| 275 |
+
}
|
| 276 |
+
});
|
| 277 |
});
|
| 278 |
+
}
|
| 279 |
|
| 280 |
+
setTimeout(() => {
|
| 281 |
+
if (!found) alert(`Không tìm thấy từ khóa "${query}" trong tài liệu này.`);
|
| 282 |
+
}, 1500);
|
| 283 |
+
}
|
| 284 |
|
| 285 |
+
// Chức năng slideshow
|
| 286 |
+
function startSlideshow() {
|
| 287 |
+
if (currentDocIndex === -1 || totalPages <= 1) return;
|
| 288 |
+
stopSlideshow(); // Dừng nếu đang chạy
|
| 289 |
+
const interval = parseInt(intervalSelect.value);
|
| 290 |
+
slideshowInterval = setInterval(() => {
|
| 291 |
+
if (currentPage < totalPages) {
|
| 292 |
+
currentPage++;
|
| 293 |
+
pageInfo.textContent = `Trang: ${currentPage} / ${totalPages}`;
|
| 294 |
+
renderPage(currentPage);
|
| 295 |
+
} else {
|
| 296 |
+
stopSlideshow();
|
| 297 |
+
}
|
| 298 |
+
}, interval);
|
| 299 |
}
|
| 300 |
|
| 301 |
+
function stopSlideshow() {
|
| 302 |
+
if (slideshowInterval) clearInterval(slideshowInterval);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
// Khởi động ứng dụng
|
| 306 |
+
updatePdfGrid();
|
|
|
|
| 307 |
</script>
|
| 308 |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=bep40/invoice" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 309 |
</html>
|
prompts.txt
CHANGED
|
@@ -1,4 +1,10 @@
|
|
| 1 |
Tạo 1 app tính giá và in hoá đơn theo mẫu
|
| 2 |
Tạo 1 app tính giá và in hoá đơn theo mẫu có logo, hoá đơn có các thông tin số thứ tự, mã sản phẩm, tên sản phẩm, số lượng, đơn giá, giá chiết khấu, tên khách hàng, địa chỉ, số điện thoại, ghi chú
|
| 3 |
Tạo 1 app tính giá và in hoá đơn theo mẫu có logo, hoá đơn có các thông tin số thứ tự, mã sản phẩm, tên sản phẩm, số lượng, đơn giá, giá chiết khấu, tên khách hàng, địa chỉ, số điện thoại, ghi chú
|
| 4 |
-
Tạo 1 app tính giá và in hoá đơn theo mẫu có logo, hoá đơn có các thông tin số thứ tự, mã sản phẩm, tên sản phẩm, số lượng, đơn giá, giá chiết khấu, tên khách hàng, địa chỉ, số điện thoại, ghi chú. Có thể in ra file pdf
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
Tạo 1 app tính giá và in hoá đơn theo mẫu
|
| 2 |
Tạo 1 app tính giá và in hoá đơn theo mẫu có logo, hoá đơn có các thông tin số thứ tự, mã sản phẩm, tên sản phẩm, số lượng, đơn giá, giá chiết khấu, tên khách hàng, địa chỉ, số điện thoại, ghi chú
|
| 3 |
Tạo 1 app tính giá và in hoá đơn theo mẫu có logo, hoá đơn có các thông tin số thứ tự, mã sản phẩm, tên sản phẩm, số lượng, đơn giá, giá chiết khấu, tên khách hàng, địa chỉ, số điện thoại, ghi chú
|
| 4 |
+
Tạo 1 app tính giá và in hoá đơn theo mẫu có logo, hoá đơn có các thông tin số thứ tự, mã sản phẩm, tên sản phẩm, số lượng, đơn giá, giá chiết khấu, tên khách hàng, địa chỉ, số điện thoại, ghi chú. Có thể in ra file pdf
|
| 5 |
+
Tạo app xem file PDF dạng slideshow và tìm kiếm được text trên file pdf
|
| 6 |
+
Tạo app xem file PDF dạng slideshow và tìm kiếm được text và tương tác trên file pdf có sẵn
|
| 7 |
+
Tạo app danh sách các file PDF dạng slideshow và tìm kiếm được text trên file pdf
|
| 8 |
+
Tạo app danh sách file PDF có sẵn dạng slideshow và tìm kiếm được text trên file pdf
|
| 9 |
+
Tạo app xem danh sách file PDF có sẵn dạng lưới và xem slideshow và tìm kiếm được text trên file pdf
|
| 10 |
+
Tạo app danh sách file PDF có sẵn trình bày dưới hình thức trang bìa và xem dạng slideshow và tìm kiếm được text trên file pdf
|