feat(前端): 优化表单输入框样式并重构分页组件

- 为所有管理页面和登录注册页添加统一的输入框聚焦样式
- 重构分页组件为通用实现,支持页码跳转和省略号显示
- 优化分页交互体验,减少代码重复
This commit is contained in:
祀梦
2025-12-22 23:54:11 +08:00
parent b1da021185
commit 84d5840391
12 changed files with 245 additions and 67 deletions

Binary file not shown.

View File

@@ -221,29 +221,92 @@ class AdminManager {
}
}
renderPagination(pagination) {
const el = document.getElementById('pagination');
renderGenericPagination(containerId, pagination, callbackName) {
const el = document.getElementById(containerId);
if (!el) return;
const { page, pages } = pagination;
if (pages <= 0) {
el.innerHTML = '';
return;
}
let html = '';
if (pagination.page > 1) {
html += `<li class="page-item"><a class="page-link" href="#" onclick="window.adminManager.changePage(${pagination.page - 1})">上一页</a></li>`;
// Previous page
if (page > 1) {
html += `<li class="page-item"><a class="page-link" href="javascript:void(0)" onclick="window.adminManager.${callbackName}(${page - 1})">上一页</a></li>`;
} else {
html += `<li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>`;
html += `<li class="page-item disabled"><a class="page-link" href="javascript:void(0)">上一页</a></li>`;
}
for (let i = 1; i <= pagination.pages; i++) {
html += `<li class="page-item ${i === pagination.page ? 'active' : ''}"><a class="page-link" href="#" onclick="window.adminManager.changePage(${i})">${i}</a></li>`;
// Page numbers with ellipsis
if (pages <= 7) {
for (let i = 1; i <= pages; i++) {
html += `<li class="page-item ${i === page ? 'active' : ''}"><a class="page-link" href="javascript:void(0)" onclick="window.adminManager.${callbackName}(${i})">${i}</a></li>`;
}
} else {
// First page
html += `<li class="page-item ${page === 1 ? 'active' : ''}"><a class="page-link" href="javascript:void(0)" onclick="window.adminManager.${callbackName}(1)">1</a></li>`;
if (page > 4) {
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
}
// Middle pages
let start = Math.max(2, page - 2);
let end = Math.min(pages - 1, page + 2);
if (page <= 4) {
start = 2;
end = 5;
} else if (page >= pages - 3) {
start = pages - 4;
end = pages - 1;
}
for (let i = start; i <= end; i++) {
html += `<li class="page-item ${i === page ? 'active' : ''}"><a class="page-link" href="javascript:void(0)" onclick="window.adminManager.${callbackName}(${i})">${i}</a></li>`;
}
if (page < pages - 3) {
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
}
// Last page
html += `<li class="page-item ${page === pages ? 'active' : ''}"><a class="page-link" href="javascript:void(0)" onclick="window.adminManager.${callbackName}(${pages})">${pages}</a></li>`;
}
if (pagination.page < pagination.pages) {
html += `<li class="page-item"><a class="page-link" href="#" onclick="window.adminManager.changePage(${pagination.page + 1})">下一页</a></li>`;
// Next page
if (page < pages) {
html += `<li class="page-item"><a class="page-link" href="javascript:void(0)" onclick="window.adminManager.${callbackName}(${page + 1})">下一页</a></li>`;
} else {
html += `<li class="page-item disabled"><a class="page-link" href="#">下一页</a></li>`;
html += `<li class="page-item disabled"><a class="page-link" href="javascript:void(0)">下一页</a></li>`;
}
// Jump to page
html += `
<li class="page-item ms-3 d-flex align-items-center">
<div class="input-group input-group-sm" style="width: auto;">
<span class="input-group-text bg-light border-end-0">跳转至</span>
<input type="number" class="form-control text-center" style="width: 60px;" min="1" max="${pages}" value="${page}"
onkeydown="if(event.keyCode==13) {
const p = parseInt(this.value);
if(p >= 1 && p <= ${pages}) window.adminManager.${callbackName}(p);
else alert('请输入正确的页码(1-${pages})');
}">
<span class="input-group-text bg-light border-start-0">页 / 共 ${pages} 页</span>
</div>
</li>
`;
el.innerHTML = html;
}
renderPagination(pagination) {
this.renderGenericPagination('pagination', pagination, 'changePage');
}
changePage(page) {
this.currentPage = page;
this.loadUsers();
@@ -426,26 +489,7 @@ class AdminManager {
}
renderStudentPagination(pagination) {
const el = document.getElementById('studentPagination');
let html = '';
if (pagination.page > 1) {
html += `<li class="page-item"><a class="page-link" href="#" onclick="window.adminManager.changeStudentPage(${pagination.page - 1})">上一页</a></li>`;
} else {
html += `<li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>`;
}
for (let i = 1; i <= pagination.pages; i++) {
html += `<li class="page-item ${i === pagination.page ? 'active' : ''}"><a class="page-link" href="#" onclick="window.adminManager.changeStudentPage(${i})">${i}</a></li>`;
}
if (pagination.page < pagination.pages) {
html += `<li class="page-item"><a class="page-link" href="#" onclick="window.adminManager.changeStudentPage(${pagination.page + 1})">下一页</a></li>`;
} else {
html += `<li class="page-item disabled"><a class="page-link" href="#">下一页</a></li>`;
}
el.innerHTML = html;
this.renderGenericPagination('studentPagination', pagination, 'changeStudentPage');
}
changeStudentPage(page) {
@@ -626,26 +670,7 @@ class AdminManager {
}
renderTeacherPagination(pagination) {
const el = document.getElementById('teacherPagination');
let html = '';
if (pagination.page > 1) {
html += `<li class="page-item"><a class="page-link" href="#" onclick="window.adminManager.changeTeacherPage(${pagination.page - 1})">上一页</a></li>`;
} else {
html += `<li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>`;
}
for (let i = 1; i <= pagination.pages; i++) {
html += `<li class="page-item ${i === pagination.page ? 'active' : ''}"><a class="page-link" href="#" onclick="window.adminManager.changeTeacherPage(${i})">${i}</a></li>`;
}
if (pagination.page < pagination.pages) {
html += `<li class="page-item"><a class="page-link" href="#" onclick="window.adminManager.changeTeacherPage(${pagination.page + 1})">下一页</a></li>`;
} else {
html += `<li class="page-item disabled"><a class="page-link" href="#">下一页</a></li>`;
}
el.innerHTML = html;
this.renderGenericPagination('teacherPagination', pagination, 'changeTeacherPage');
}
changeTeacherPage(page) {

View File

@@ -121,6 +121,12 @@
.main-content { margin-left: 0; }
.sidebar.active { left: 0; }
}
/* 表单控件聚焦样式优化 */
.form-control:focus, .form-select:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.1);
}
</style>
</head>
<body>

View File

@@ -121,6 +121,12 @@
.main-content { margin-left: 0; }
.sidebar.active { left: 0; }
}
/* 表单控件聚焦样式优化 */
.form-control:focus, .form-select:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.1);
}
</style>
</head>
<body>

View File

@@ -121,6 +121,12 @@
.main-content { margin-left: 0; }
.sidebar.active { left: 0; }
}
/* 表单控件聚焦样式优化 */
.form-control:focus, .form-select:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.1);
}
</style>
</head>
<body>

View File

@@ -121,6 +121,40 @@
.main-content { margin-left: 0; }
.sidebar.active { left: 0; }
}
/* 输入框聚焦样式优化 */
.input-group {
border: 1px solid #dee2e6;
border-radius: 0.5rem;
overflow: hidden;
transition: all 0.2s;
background-color: #fff;
}
.input-group:focus-within {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.1);
}
.input-group-text {
background-color: transparent;
border: none;
color: var(--secondary-color);
padding-left: 1rem;
padding-right: 0.5rem;
}
.form-control {
border: none !important;
}
.form-control:focus {
box-shadow: none;
}
.input-group:focus-within .input-group-text {
color: var(--primary-color);
}
</style>
</head>
<body>

View File

@@ -121,6 +121,12 @@
.main-content { margin-left: 0; }
.sidebar.active { left: 0; }
}
/* 表单控件聚焦样式优化 */
.form-control:focus, .form-select:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.1);
}
</style>
</head>
<body>

View File

@@ -121,6 +121,40 @@
.main-content { margin-left: 0; }
.sidebar.active { left: 0; }
}
/* 输入框聚焦样式优化 */
.input-group {
border: 1px solid #dee2e6;
border-radius: 0.5rem;
overflow: hidden;
transition: all 0.2s;
background-color: #fff;
}
.input-group:focus-within {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.1);
}
.input-group-text {
background-color: transparent;
border: none;
color: var(--secondary-color);
padding-left: 1rem;
padding-right: 0.5rem;
}
.form-control {
border: none !important;
}
.form-control:focus {
box-shadow: none;
}
.input-group:focus-within .input-group-text {
color: var(--primary-color);
}
</style>
</head>
<body>

View File

@@ -121,6 +121,40 @@
.main-content { margin-left: 0; }
.sidebar.active { left: 0; }
}
/* 输入框聚焦样式优化 */
.input-group {
border: 1px solid #dee2e6;
border-radius: 0.5rem;
overflow: hidden;
transition: all 0.2s;
background-color: #fff;
}
.input-group:focus-within {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.1);
}
.input-group-text {
background-color: transparent;
border: none;
color: var(--secondary-color);
padding-left: 1rem;
padding-right: 0.5rem;
}
.form-control {
border: none !important;
}
.form-control:focus {
box-shadow: none;
}
.input-group:focus-within .input-group-text {
color: var(--primary-color);
}
</style>
</head>
<body>

View File

@@ -66,11 +66,6 @@
margin-bottom: 1.25rem;
}
.form-control:focus {
box-shadow: none;
border-color: #764ba2;
}
.btn-login {
background: var(--primary-gradient);
border: none;
@@ -104,19 +99,38 @@
text-decoration: underline;
}
.input-group {
border: 1px solid #dee2e6;
border-radius: 0.75rem;
overflow: hidden;
transition: border-color 0.2s, box-shadow 0.2s;
background-color: #fff;
}
.input-group:focus-within {
border-color: #764ba2;
box-shadow: 0 0 0 0.2rem rgba(118, 75, 162, 0.1);
}
.input-group-text {
background-color: transparent;
border-right: none;
border: none;
color: #adb5bd;
padding-left: 1rem;
padding-right: 0.5rem;
}
.form-control {
border-left: none;
.form-control, .form-select {
border: none !important;
padding-left: 0.5rem;
}
.form-control:focus + .input-group-text,
.input-group-text:focus-within {
border-color: #764ba2;
.form-control:focus, .form-select:focus {
box-shadow: none;
}
.input-group:focus-within .input-group-text i {
color: #764ba2;
}
/* 角色图标 */

View File

@@ -96,26 +96,39 @@
text-decoration: underline;
}
.input-group {
border: 1px solid #dee2e6;
border-radius: 0.75rem;
overflow: hidden;
transition: border-color 0.2s, box-shadow 0.2s;
background-color: #fff;
}
.input-group:focus-within {
border-color: #764ba2;
box-shadow: 0 0 0 0.2rem rgba(118, 75, 162, 0.1);
}
.input-group-text {
background-color: transparent;
border-right: none;
border: none;
color: #adb5bd;
width: 45px;
justify-content: center;
padding-left: 1rem;
}
.form-control, .form-select {
border-left: none;
border: none !important;
padding-left: 0.5rem;
}
.form-control:focus, .form-select:focus {
box-shadow: none;
border-color: #764ba2;
}
.form-control:focus + .input-group-text,
.input-group-text:focus-within {
border-color: #764ba2;
.input-group:focus-within .input-group-text i {
color: #764ba2;
}
#classField {