bep40 commited on
Commit
bfbccdc
·
verified ·
1 Parent(s): 6b84c10

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +262 -235
  2. 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 Tính giá In Hóa Đơn</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
- <!-- jsPDF Library -->
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
10
  <style>
11
- @media print {
12
- body * {
13
- visibility: hidden;
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
- .invoice-table th, .invoice-table td {
32
- border: 1px solid #ccc;
33
- padding: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
  </style>
37
  </head>
38
- <body class="bg-gray-100 text-gray-800 font-sans">
39
 
40
- <!-- Phần giao diện chính -->
41
- <div id="app" class="max-w-6xl mx-auto p-6 bg-white rounded shadow-lg mt-10">
42
- <h1 class="text-3xl font-bold mb-6 text-center text-blue-600">Ứng dụng Tính giá In Hóa Đơn</h1>
 
43
 
44
- <!-- Thông tin khách hàng -->
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
- <!-- Thông tin sản phẩm -->
52
- <div class="grid grid-cols-1 md:grid-cols-6 gap-4 mb-4">
53
- <input id="productIndex" type="number" placeholder="STT" class="border p-2 rounded text-center" disabled>
54
- <input id="productCode" type="text" placeholder="Mã sản phẩm" class="border p-2 rounded">
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
- <div class="mb-4">
62
- <textarea id="note" placeholder="Ghi chú" class="border p-2 rounded w-full" rows="2"></textarea>
63
- </div>
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
- <!-- Bảng hóa đơn -->
76
- <div class="overflow-x-auto">
77
- <table class="min-w-full border-collapse border border-gray-300">
78
- <thead>
79
- <tr class="bg-gray-200">
80
- <th class="border border-gray-300 px-4 py-2">STT</th>
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
- <!-- Bảng in -->
122
- <table class="min-w-full border-collapse border border-gray-300 invoice-table">
123
- <thead>
124
- <tr class="bg-gray-200">
125
- <th class="border border-gray-300 px-4 py-2">STT</th>
126
- <th class="border border-gray-300 px-4 py-2">Mã SP</th>
127
- <th class="border border-gray-300 px-4 py-2">Tên SP</th>
128
- <th class="border border-gray-300 px-4 py-2">SL</th>
129
- <th class="border border-gray-300 px-4 py-2">Đơn giá</th>
130
- <th class="border border-gray-300 px-4 py-2">Chiết khấu (%)</th>
131
- <th class="border border-gray-300 px-4 py-2">Thành tiền</th>
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
- <div class="mt-6 text-right font-bold text-xl">
140
- Tổng cộng: <span id="totalPrintAmount">0</span> VNĐ
 
 
 
141
  </div>
142
 
143
- <div class="mt-4">
144
- <p><strong>Ghi chú:</strong> <span id="printNote"></span></p>
145
- </div>
146
 
147
- <p class="mt-6 text-center text-sm text-gray-500">Cảm ơn quý khách và hẹn gặp lại!</p>
148
- </div>
 
149
 
150
  <script>
151
- let total = 0;
152
- let index = 1;
153
-
154
- function calculateTotal() {
155
- const price = parseFloat(document.getElementById('price').value) || 0;
156
- const quantity = parseFloat(document.getElementById('quantity').value) || 0;
157
- const discount = parseFloat(document.getElementById('discount').value) || 0;
158
-
159
- const discountAmount = price * quantity * (discount / 100);
160
- const finalAmount = price * quantity - discountAmount;
161
-
162
- document.getElementById('totalInput').value = finalAmount.toLocaleString('vi-VN') + " VNĐ";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  }
164
 
165
- function addToInvoice() {
166
- const code = document.getElementById('productCode').value.trim();
167
- const name = document.getElementById('productName').value.trim();
168
- const price = parseFloat(document.getElementById('price').value);
169
- const quantity = parseFloat(document.getElementById('quantity').value);
170
- const discount = parseFloat(document.getElementById('discount').value);
171
- const note = document.getElementById('note').value.trim();
 
 
 
 
172
 
173
- if (!name || isNaN(price) || isNaN(quantity) || price <= 0 || quantity <= 0) {
174
- alert("Vui lòng nhập đầy đủ thông tin hợp lệ!");
 
 
175
  return;
176
  }
177
 
178
- const discountAmount = price * quantity * (discount / 100);
179
- const amount = price * quantity - discountAmount;
180
-
181
- // Thêm vào bảng hiển thị
182
- const row = document.createElement('tr');
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
- // Cập nhật ngày
218
- const today = new Date().toLocaleDateString('vi-VN');
219
- document.getElementById('invoiceDate').textContent = today;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
- // Cập nhật số thứ tự
222
- document.getElementById('productIndex').value = index++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
- // Reset form
225
- document.getElementById('productCode').value = '';
226
- document.getElementById('productName').value = '';
227
- document.getElementById('price').value = '';
228
- document.getElementById('quantity').value = '';
229
- document.getElementById('discount').value = '0';
230
- document.getElementById('note').value = '';
231
- document.getElementById('totalInput').value = '';
 
232
  }
233
 
234
- function downloadPDF() {
235
- const { jsPDF } = window.jspdf;
236
- const doc = new jsPDF();
 
 
 
 
 
 
237
 
238
- // Tạo nội dung PDF từ phần in hóa đơn
239
- const invoice = document.getElementById("invoice");
240
- const tempContainer = document.createElement("div");
241
- tempContainer.innerHTML = invoice.innerHTML;
242
- tempContainer.style.position = "absolute";
243
- tempContainer.style.left = "-9999px";
244
- document.body.appendChild(tempContainer);
245
 
246
- const tables = tempContainer.querySelectorAll("table");
247
- tables.forEach(table => {
248
- table.style.width = "100%";
249
- table.style.fontSize = "12px";
250
- const rows = table.querySelectorAll("tr");
251
- rows.forEach(row => {
252
- row.style.border = "1px solid #000";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  });
254
- });
255
 
256
- const html = tempContainer.innerHTML;
257
- const divToPrint = document.createElement("div");
258
- divToPrint.innerHTML = html;
259
- document.body.appendChild(divToPrint);
260
 
261
- doc.html(divToPrint, {
262
- callback: function (doc) {
263
- doc.save("HoaDon_BanHang.pdf");
264
- document.body.removeChild(divToPrint);
265
- },
266
- x: 10,
267
- y: 10,
268
- width: 180,
269
- windowWidth: 600
270
- });
 
 
 
 
271
  }
272
 
273
- // Thiết lập giá chiết khấu mặc định là 0 nếu không nhập
274
- document.getElementById('discount').addEventListener('input', function () {
275
- if (this.value === '') {
276
- this.value = '0';
277
- }
278
- calculateTotal();
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ếutì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
+ &copy; 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