|
130 | 130 | </div> |
131 | 131 | <div class="overflow-y-auto flex-1"> |
132 | 132 | {{if .AllRequests}} |
133 | | - <ul class="divide-y"> |
| 133 | + <ul class="divide-y" id="requestList"> |
134 | 134 | {{range .AllRequests}} |
135 | | - <a href="/?view_id={{.ID}}" class="block p-4 hover:bg-gray-50 {{if isCurrent .ID $.SelectedRequest}}bg-indigo-50 border-l-4 border-indigo-500{{end}}"> |
| 135 | + <a href="#" data-request-id="{{.ID}}" class="request-link block p-4 hover:bg-gray-50 {{if isCurrent .ID $.SelectedRequest}}bg-indigo-50 border-l-4 border-indigo-500{{end}}"> |
136 | 136 | <div class="flex justify-between items-center mb-1"> |
137 | 137 | <div class="font-bold truncate {{if isCurrent .ID $.SelectedRequest}}text-indigo-700{{else}}text-gray-800{{end}}"> |
138 | 138 | <span class="px-2 mr-2 text-xs leading-5 font-semibold rounded-full |
|
156 | 156 | </div> |
157 | 157 | {{end}} |
158 | 158 | </div> |
| 159 | + <!-- Pagination Controls --> |
| 160 | + <div id="paginationControls" class="p-4 border-t bg-gray-50"> |
| 161 | + <div class="flex items-center justify-between text-sm"> |
| 162 | + <div class="text-gray-600"> |
| 163 | + <span id="paginationInfo">第 1 页,共 1 页 (总计 {{len .AllRequests}} 个请求)</span> |
| 164 | + </div> |
| 165 | + <div class="flex space-x-2"> |
| 166 | + <button id="prevPageBtn" class="px-3 py-1 text-sm bg-gray-200 text-gray-600 rounded hover:bg-gray-300 disabled:opacity-50 disabled:cursor-not-allowed" disabled> |
| 167 | + 上一页 |
| 168 | + </button> |
| 169 | + <button id="nextPageBtn" class="px-3 py-1 text-sm bg-gray-200 text-gray-600 rounded hover:bg-gray-300 disabled:opacity-50 disabled:cursor-not-allowed"> |
| 170 | + 下一页 |
| 171 | + </button> |
| 172 | + </div> |
| 173 | + </div> |
| 174 | + </div> |
159 | 175 | </aside> |
160 | 176 |
|
161 | 177 | <!-- Right Column: Request Details --> |
|
244 | 260 | // Initialize language first |
245 | 261 | initLanguage(); |
246 | 262 |
|
| 263 | + // --- Pagination variables --- |
| 264 | + let currentPage = 1; |
| 265 | + let totalPages = 1; |
| 266 | + let isUpdating = false; |
| 267 | + |
247 | 268 | // --- Auto-refresh logic --- |
248 | 269 | const checkbox = document.getElementById('autoRefreshCheckbox'); |
249 | 270 | const intervalInput = document.getElementById('refreshIntervalInput'); |
250 | 271 | const manualRefreshButton = document.getElementById('manualRefreshButton'); |
251 | 272 | let refreshInterval; |
252 | 273 |
|
| 274 | + // --- Pagination controls --- |
| 275 | + const prevPageBtn = document.getElementById('prevPageBtn'); |
| 276 | + const nextPageBtn = document.getElementById('nextPageBtn'); |
| 277 | + const paginationInfo = document.getElementById('paginationInfo'); |
| 278 | + const paginationControls = document.getElementById('paginationControls'); |
| 279 | + |
253 | 280 | function startRefresh() { |
254 | 281 | if (refreshInterval) clearInterval(refreshInterval); |
255 | 282 | let interval = parseInt(intervalInput.value, 10); |
|
273 | 300 | } |
274 | 301 | } |
275 | 302 |
|
| 303 | + // Function to update pagination info |
| 304 | + function updatePaginationInfo(data) { |
| 305 | + const { page, total_pages, total } = data; |
| 306 | + paginationInfo.textContent = `第 ${page} 页,共 ${total_pages} 页 (总计 ${total} 个请求)`; |
| 307 | + |
| 308 | + prevPageBtn.disabled = !data.has_prev; |
| 309 | + nextPageBtn.disabled = !data.has_next; |
| 310 | + |
| 311 | + currentPage = page; |
| 312 | + totalPages = total_pages; |
| 313 | + |
| 314 | + // Show/hide pagination controls based on whether there are multiple pages |
| 315 | + if (total_pages > 1) { |
| 316 | + paginationControls.classList.remove('hidden'); |
| 317 | + } else { |
| 318 | + paginationControls.classList.add('hidden'); |
| 319 | + } |
| 320 | + } |
| 321 | + |
276 | 322 | // Function to update only the request list via AJAX |
277 | | - function updateRequestList() { |
278 | | - return fetch('/api/requests') |
| 323 | + function updateRequestList(page = currentPage) { |
| 324 | + if (isUpdating) return; |
| 325 | + isUpdating = true; |
| 326 | + |
| 327 | + return fetch(`/api/requests?page=${page}&limit=20`) |
279 | 328 | .then(response => response.json()) |
280 | | - .then(requests => { |
| 329 | + .then(data => { |
281 | 330 | const requestList = document.querySelector('aside .overflow-y-auto'); |
282 | 331 | const currentViewId = new URLSearchParams(window.location.search).get('view_id'); |
283 | 332 |
|
284 | | - if (requests && requests.length > 0) { |
| 333 | + updatePaginationInfo(data); |
| 334 | + |
| 335 | + if (data.requests && data.requests.length > 0) { |
285 | 336 | const ul = document.createElement('ul'); |
286 | 337 | ul.className = 'divide-y'; |
| 338 | + ul.id = 'requestList'; |
287 | 339 |
|
288 | | - requests.forEach(request => { |
| 340 | + data.requests.forEach(request => { |
289 | 341 | const li = document.createElement('a'); |
290 | | - li.href = `/?view_id=${request.ID}`; |
291 | | - li.className = `block p-4 hover:bg-gray-50 ${currentViewId == request.ID ? 'bg-indigo-50 border-l-4 border-indigo-500' : ''}`; |
| 342 | + li.href = '#'; |
| 343 | + li.setAttribute('data-request-id', request.ID); |
| 344 | + li.className = `request-link block p-4 hover:bg-gray-50 ${currentViewId == request.ID ? 'bg-indigo-50 border-l-4 border-indigo-500' : ''}`; |
292 | 345 |
|
293 | 346 | const methodColor = getMethodColor(request.Method); |
294 | 347 | const timestamp = new Date(request.Timestamp).toLocaleString(); |
|
305 | 358 | <div class="text-xs text-gray-500">${timestamp}</div> |
306 | 359 | `; |
307 | 360 |
|
| 361 | + // Add click event listener |
| 362 | + li.addEventListener('click', handleRequestClick); |
| 363 | + |
308 | 364 | ul.appendChild(li); |
309 | 365 | }); |
310 | 366 |
|
|
320 | 376 | }) |
321 | 377 | .catch(error => { |
322 | 378 | console.error('Error updating request list:', error); |
| 379 | + }) |
| 380 | + .finally(() => { |
| 381 | + isUpdating = false; |
323 | 382 | }); |
324 | 383 | } |
325 | 384 |
|
|
334 | 393 | } |
335 | 394 | } |
336 | 395 |
|
| 396 | + // Pagination button event listeners |
| 397 | + prevPageBtn.addEventListener('click', () => { |
| 398 | + if (currentPage > 1) { |
| 399 | + updateRequestList(currentPage - 1); |
| 400 | + } |
| 401 | + }); |
| 402 | + |
| 403 | + nextPageBtn.addEventListener('click', () => { |
| 404 | + if (currentPage < totalPages) { |
| 405 | + updateRequestList(currentPage + 1); |
| 406 | + } |
| 407 | + }); |
| 408 | + |
337 | 409 | checkbox.addEventListener('change', () => { |
338 | 410 | localStorage.setItem('autoRefreshInterval', intervalInput.value); |
339 | 411 | if (checkbox.checked) { |
|
398 | 470 | } |
399 | 471 | toggleManualRefreshButton(); // Initialize manual refresh button visibility |
400 | 472 |
|
| 473 | + // Initialize pagination and request list |
| 474 | + updateRequestList(); |
| 475 | + |
| 476 | + // Handle request link clicks |
| 477 | + function handleRequestClick(event) { |
| 478 | + event.preventDefault(); |
| 479 | + const requestId = event.currentTarget.getAttribute('data-request-id'); |
| 480 | + if (requestId) { |
| 481 | + // Update URL without page reload |
| 482 | + const newUrl = new URL(window.location); |
| 483 | + newUrl.searchParams.set('view_id', requestId); |
| 484 | + window.history.pushState({}, '', newUrl); |
| 485 | + |
| 486 | + // Update the display |
| 487 | + loadRequestDetails(requestId); |
| 488 | + } |
| 489 | + } |
| 490 | + |
| 491 | + // Add click event listeners to existing request links |
| 492 | + document.querySelectorAll('.request-link').forEach(link => { |
| 493 | + link.addEventListener('click', handleRequestClick); |
| 494 | + }); |
| 495 | + |
| 496 | + // Function to load request details via AJAX |
| 497 | + function loadRequestDetails(requestId) { |
| 498 | + // You can implement this to load request details via AJAX |
| 499 | + // For now, just reload the page |
| 500 | + window.location.href = `/?view_id=${requestId}`; |
| 501 | + } |
| 502 | + |
401 | 503 | // --- Collapsible sections logic --- |
402 | 504 | const sections = ['headers', 'body']; |
403 | 505 |
|
|
0 commit comments