feat(review): 添加分页跳转和记住暗号功能
- 新增分页跳转下拉菜单,实现快速跳转任意页码 - 增加分页栏样式,调整按钮与选择框的尺寸与间距 - 在登录面板添加“记住暗号”复选框及相关样式 - 登录时读取本地存储的暗号并自动填充 - 登录成功时根据复选框状态保存或清除本地存储的暗号 - 分页按钮和跳转选择框事件联动,实现页面数据刷新更新
Showing
1 changed file
with
57 additions
and
4 deletions
| ... | @@ -517,6 +517,26 @@ | ... | @@ -517,6 +517,26 @@ |
| 517 | align-items: center; | 517 | align-items: center; |
| 518 | } | 518 | } |
| 519 | 519 | ||
| 520 | .page-bar { | ||
| 521 | display: flex; | ||
| 522 | align-items: center; | ||
| 523 | gap: 6px; | ||
| 524 | margin-bottom: 10px; | ||
| 525 | } | ||
| 526 | |||
| 527 | .page-bar button { | ||
| 528 | height: 30px; | ||
| 529 | padding: 0 12px; | ||
| 530 | font-size: 13px; | ||
| 531 | } | ||
| 532 | |||
| 533 | .page-bar select { | ||
| 534 | height: 30px; | ||
| 535 | font-size: 13px; | ||
| 536 | min-width: 80px; | ||
| 537 | text-align: center; | ||
| 538 | } | ||
| 539 | |||
| 520 | .review-bar button { | 540 | .review-bar button { |
| 521 | background: #fff; | 541 | background: #fff; |
| 522 | color: var(--text); | 542 | color: var(--text); |
| ... | @@ -574,6 +594,8 @@ | ... | @@ -574,6 +594,8 @@ |
| 574 | .login-panel input { width: 100%; box-sizing: border-box; } | 594 | .login-panel input { width: 100%; box-sizing: border-box; } |
| 575 | .login-panel button { width: 100%; margin-top: 16px; } | 595 | .login-panel button { width: 100%; margin-top: 16px; } |
| 576 | .login-error { min-height: 20px; margin-top: 10px; color: #b42318; font-size: 13px; } | 596 | .login-error { min-height: 20px; margin-top: 10px; color: #b42318; font-size: 13px; } |
| 597 | .login-remember { display: flex; align-items: center; gap: 6px; margin-top: 10px; font-size: 13px; color: var(--muted); cursor: pointer; user-select: none; } | ||
| 598 | .login-remember input { width: auto; height: auto; margin: 0; cursor: pointer; } | ||
| 577 | 599 | ||
| 578 | @media (max-width: 1100px) { | 600 | @media (max-width: 1100px) { |
| 579 | main { grid-template-columns: 1fr; height: auto; } | 601 | main { grid-template-columns: 1fr; height: auto; } |
| ... | @@ -594,6 +616,7 @@ | ... | @@ -594,6 +616,7 @@ |
| 594 | <input id="loginReviewer" maxlength="64" autocomplete="username" required> | 616 | <input id="loginReviewer" maxlength="64" autocomplete="username" required> |
| 595 | <label for="loginAccessCode">暗号</label> | 617 | <label for="loginAccessCode">暗号</label> |
| 596 | <input id="loginAccessCode" type="password" autocomplete="current-password" required> | 618 | <input id="loginAccessCode" type="password" autocomplete="current-password" required> |
| 619 | <label class="login-remember"><input id="rememberAccessCode" type="checkbox"> 记住暗号</label> | ||
| 597 | <button id="loginBtn" type="submit">进入编辑</button> | 620 | <button id="loginBtn" type="submit">进入编辑</button> |
| 598 | <div id="loginError" class="login-error"></div> | 621 | <div id="loginError" class="login-error"></div> |
| 599 | </form> | 622 | </form> |
| ... | @@ -652,11 +675,12 @@ | ... | @@ -652,11 +675,12 @@ |
| 652 | <span id="sampleCount" class="pill"></span> | 675 | <span id="sampleCount" class="pill"></span> |
| 653 | </div> | 676 | </div> |
| 654 | <div class="section-body"> | 677 | <div class="section-body"> |
| 655 | <div id="queryList" class="query-list"></div> | 678 | <div class="page-bar"> |
| 656 | <div class="review-bar" style="margin-top:10px"> | ||
| 657 | <button id="prevPageBtn" class="secondary">上一页</button> | 679 | <button id="prevPageBtn" class="secondary">上一页</button> |
| 680 | <select id="pageJumpSelect"></select> | ||
| 658 | <button id="nextPageBtn" class="secondary">下一页</button> | 681 | <button id="nextPageBtn" class="secondary">下一页</button> |
| 659 | </div> | 682 | </div> |
| 683 | <div id="queryList" class="query-list"></div> | ||
| 660 | </div> | 684 | </div> |
| 661 | </div> | 685 | </div> |
| 662 | </aside> | 686 | </aside> |
| ... | @@ -706,6 +730,7 @@ | ... | @@ -706,6 +730,7 @@ |
| 706 | reloadBtn: document.getElementById('reloadBtn'), | 730 | reloadBtn: document.getElementById('reloadBtn'), |
| 707 | prevPageBtn: document.getElementById('prevPageBtn'), | 731 | prevPageBtn: document.getElementById('prevPageBtn'), |
| 708 | nextPageBtn: document.getElementById('nextPageBtn'), | 732 | nextPageBtn: document.getElementById('nextPageBtn'), |
| 733 | pageJumpSelect: document.getElementById('pageJumpSelect'), | ||
| 709 | 734 | ||
| 710 | metrics: document.getElementById('metrics'), | 735 | metrics: document.getElementById('metrics'), |
| 711 | sampleCount: document.getElementById('sampleCount'), | 736 | sampleCount: document.getElementById('sampleCount'), |
| ... | @@ -718,7 +743,8 @@ | ... | @@ -718,7 +743,8 @@ |
| 718 | loginReviewer: document.getElementById('loginReviewer'), | 743 | loginReviewer: document.getElementById('loginReviewer'), |
| 719 | loginAccessCode: document.getElementById('loginAccessCode'), | 744 | loginAccessCode: document.getElementById('loginAccessCode'), |
| 720 | loginBtn: document.getElementById('loginBtn'), | 745 | loginBtn: document.getElementById('loginBtn'), |
| 721 | loginError: document.getElementById('loginError') | 746 | loginError: document.getElementById('loginError'), |
| 747 | rememberAccessCode: document.getElementById('rememberAccessCode') | ||
| 722 | }; | 748 | }; |
| 723 | 749 | ||
| 724 | function newClientToken() { | 750 | function newClientToken() { |
| ... | @@ -728,7 +754,9 @@ | ... | @@ -728,7 +754,9 @@ |
| 728 | 754 | ||
| 729 | function showReviewLogin(prefillReviewer = '') { | 755 | function showReviewLogin(prefillReviewer = '') { |
| 730 | els.loginReviewer.value = prefillReviewer; | 756 | els.loginReviewer.value = prefillReviewer; |
| 731 | els.loginAccessCode.value = ''; | 757 | const savedCode = localStorage.getItem('l2AccessCode') || ''; |
| 758 | els.loginAccessCode.value = savedCode; | ||
| 759 | els.rememberAccessCode.checked = Boolean(savedCode); | ||
| 732 | els.loginError.textContent = ''; | 760 | els.loginError.textContent = ''; |
| 733 | els.loginOverlay.classList.remove('hidden'); | 761 | els.loginOverlay.classList.remove('hidden'); |
| 734 | window.setTimeout(() => (prefillReviewer ? els.loginAccessCode : els.loginReviewer).focus(), 0); | 762 | window.setTimeout(() => (prefillReviewer ? els.loginAccessCode : els.loginReviewer).focus(), 0); |
| ... | @@ -748,6 +776,11 @@ | ... | @@ -748,6 +776,11 @@ |
| 748 | state.authToken = session.session_token; | 776 | state.authToken = session.session_token; |
| 749 | localStorage.setItem('l2ReviewerName', state.reviewer); | 777 | localStorage.setItem('l2ReviewerName', state.reviewer); |
| 750 | sessionStorage.setItem('l2ReviewAuthToken', state.authToken); | 778 | sessionStorage.setItem('l2ReviewAuthToken', state.authToken); |
| 779 | if (els.rememberAccessCode.checked) { | ||
| 780 | localStorage.setItem('l2AccessCode', accessCode); | ||
| 781 | } else { | ||
| 782 | localStorage.removeItem('l2AccessCode'); | ||
| 783 | } | ||
| 751 | els.reviewerInput.value = state.reviewer; | 784 | els.reviewerInput.value = state.reviewer; |
| 752 | els.loginAccessCode.value = ''; | 785 | els.loginAccessCode.value = ''; |
| 753 | els.loginOverlay.classList.add('hidden'); | 786 | els.loginOverlay.classList.add('hidden'); |
| ... | @@ -767,6 +800,11 @@ | ... | @@ -767,6 +800,11 @@ |
| 767 | sessionStorage.setItem('l2ReviewClientToken', state.clientToken); | 800 | sessionStorage.setItem('l2ReviewClientToken', state.clientToken); |
| 768 | state.authToken = sessionStorage.getItem('l2ReviewAuthToken') || ''; | 801 | state.authToken = sessionStorage.getItem('l2ReviewAuthToken') || ''; |
| 769 | els.loginReviewer.value = state.reviewer; | 802 | els.loginReviewer.value = state.reviewer; |
| 803 | const savedCode = localStorage.getItem('l2AccessCode') || ''; | ||
| 804 | if (savedCode) { | ||
| 805 | els.loginAccessCode.value = savedCode; | ||
| 806 | els.rememberAccessCode.checked = true; | ||
| 807 | } | ||
| 770 | 808 | ||
| 771 | if (state.reviewer && state.authToken) { | 809 | if (state.reviewer && state.authToken) { |
| 772 | try { | 810 | try { |
| ... | @@ -1054,6 +1092,12 @@ | ... | @@ -1054,6 +1092,12 @@ |
| 1054 | } | 1092 | } |
| 1055 | els.prevPageBtn.disabled = state.page <= 1; | 1093 | els.prevPageBtn.disabled = state.page <= 1; |
| 1056 | els.nextPageBtn.disabled = !state.hasMore; | 1094 | els.nextPageBtn.disabled = !state.hasMore; |
| 1095 | // 填充页码跳转下拉 | ||
| 1096 | const jumpOptions = []; | ||
| 1097 | for (let p = 1; p <= totalPages; p++) { | ||
| 1098 | jumpOptions.push(`<option value="${p}" ${p === state.page ? 'selected' : ''}>第 ${p} 页</option>`); | ||
| 1099 | } | ||
| 1100 | els.pageJumpSelect.innerHTML = jumpOptions.join(''); | ||
| 1057 | } | 1101 | } |
| 1058 | 1102 | ||
| 1059 | function selectedQueryRows() { | 1103 | function selectedQueryRows() { |
| ... | @@ -1704,6 +1748,15 @@ | ... | @@ -1704,6 +1748,15 @@ |
| 1704 | await loadGroups(); | 1748 | await loadGroups(); |
| 1705 | renderAll(); | 1749 | renderAll(); |
| 1706 | }); | 1750 | }); |
| 1751 | els.pageJumpSelect.addEventListener('change', async () => { | ||
| 1752 | const target = Number(els.pageJumpSelect.value); | ||
| 1753 | if (!target || target === state.page) return; | ||
| 1754 | state.page = target; | ||
| 1755 | state.queryId = ''; | ||
| 1756 | state.candidateId = ''; | ||
| 1757 | await loadGroups(); | ||
| 1758 | renderAll(); | ||
| 1759 | }); | ||
| 1707 | 1760 | ||
| 1708 | async function bootstrap() { | 1761 | async function bootstrap() { |
| 1709 | await initReviewerIdentity(); | 1762 | await initReviewerIdentity(); | ... | ... |
-
Please register or sign in to post a comment