You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

286 lines
12 KiB

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>“光联万物 创芯未来”首届沪苏协同新兴产业科创大赛报名系统</title>
<link rel="stylesheet" href="../assets/bootstrap.min.css" />
<link rel="stylesheet" href="../assets/prototype.css" />
<script src="../assets/prototype-scale.js?v=20260819-hero"></script>
</head>
<body class="prototype-page admin-desktop-page">
<div class="container-fluid p-3 p-md-4">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
<h5 class="mb-0 section-title">评审员管理</h5>
</div>
<div class="reviewer-manage-shell">
<aside class="reviewer-track-panel">
<div class="reviewer-track-panel-title">赛道配置</div>
<div class="reviewer-track-tabs" id="reviewerTrackTabs"></div>
</aside>
<section class="reviewer-editor-panel">
<div class="reviewer-editor-head">
<div>
<h6 class="reviewer-track-title" id="currentTrackTitle">芯片与组件</h6>
<p class="reviewer-track-meta mb-0" id="currentTrackMeta">已配置 0 名评审员</p>
</div>
<div class="reviewer-editor-actions">
<button type="button" class="btn btn-sm btn-outline-primary" id="addReviewerBtn">新增评审员</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-sm align-middle mb-0 reviewer-manage-table">
<thead>
<tr>
<th style="width: 18%">姓名</th>
<th style="width: 22%">电话</th>
<th style="width: 24%">账户</th>
<th style="width: 24%">密码</th>
<th class="text-end" style="width: 12%">操作</th>
</tr>
</thead>
<tbody id="reviewerTableBody"></tbody>
</table>
</div>
</section>
</div>
</div>
<div class="modal fade" id="reviewerEditModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="reviewerEditTitle">新增评审员</h5>
</div>
<div class="modal-body">
<form id="reviewerEditForm" class="row g-3">
<div class="col-md-6">
<label class="form-label reviewer-edit-label">姓名 <span class="text-danger">*</span></label>
<input class="form-control" id="reviewerNameInput" required />
<div class="invalid-feedback">请填写姓名</div>
</div>
<div class="col-md-6">
<label class="form-label reviewer-edit-label">电话</label>
<input class="form-control" id="reviewerPhoneInput" />
</div>
<div class="col-md-6">
<label class="form-label reviewer-edit-label">账户 <span class="text-danger">*</span></label>
<input class="form-control" id="reviewerAccountInput" required />
<div class="invalid-feedback">请填写账户</div>
</div>
<div class="col-md-6">
<label class="form-label reviewer-edit-label">密码 <span class="text-danger">*</span></label>
<input class="form-control" id="reviewerPasswordInput" required />
<div class="invalid-feedback">请填写密码</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="reviewerEditConfirmBtn">确定</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="reviewerNoticeModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered notice-modal-dialog">
<div class="modal-content notice-modal-content notice-success">
<div class="modal-header border-0 pb-0">
<button type="button" class="btn-close ms-auto" data-bs-dismiss="modal" aria-label="关闭"></button>
</div>
<div class="modal-body notice-modal-body">
<div class="notice-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="36" height="36" fill="none" aria-hidden="true"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="1.8"/><path d="M7 12.2l3.1 3.1L17.2 8.8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<h5 class="notice-title">操作成功</h5>
<p class="notice-text">评审员信息已更新(原型演示)。</p>
</div>
<div class="modal-footer notice-modal-footer border-0">
<button type="button" class="btn btn-primary notice-ok-btn" data-bs-dismiss="modal">确定</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="reviewerDeleteModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">确认删除</h5>
</div>
<div class="modal-body">
<p class="mb-0" id="reviewerDeleteText">确定删除该评审员吗?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="reviewerDeleteConfirmBtn">确定删除</button>
</div>
</div>
</div>
</div>
<script src="../assets/bootstrap.bundle.min.js"></script>
<script>
const tracks = [
"芯片与组件",
"制造与封装",
"材料与设备",
"场景与应用"
];
const reviewersByTrack = {
"芯片与组件": [
{ name: "李明", phone: "13810001001", account: "review_xf_01", password: "XF2026@01" },
{ name: "周倩", phone: "13810001002", account: "review_xf_02", password: "XF2026@02" }
],
"制造与封装": [
{ name: "陈立", phone: "13810002001", account: "review_jk_01", password: "JK2026@01" },
{ name: "何婧", phone: "13810002002", account: "review_jk_02", password: "JK2026@02" }
],
"材料与设备": [
{ name: "王越", phone: "13810003001", account: "review_wl_01", password: "WL2026@01" },
{ name: "赵琳", phone: "13810003002", account: "review_wl_02", password: "WL2026@02" }
],
"场景与应用": [
{ name: "孙航", phone: "13810004001", account: "review_ai_01", password: "AI2026@01" },
{ name: "顾言", phone: "13810004002", account: "review_ai_02", password: "AI2026@02" }
]
};
let currentTrack = tracks[0];
let editingIndex = null;
let pendingDeleteIndex = null;
const trackTabs = document.getElementById("reviewerTrackTabs");
const tableBody = document.getElementById("reviewerTableBody");
const currentTrackTitle = document.getElementById("currentTrackTitle");
const currentTrackMeta = document.getElementById("currentTrackMeta");
const editModalEl = document.getElementById("reviewerEditModal");
const editModal = new bootstrap.Modal(editModalEl);
const editForm = document.getElementById("reviewerEditForm");
const editTitle = document.getElementById("reviewerEditTitle");
const reviewerNameInput = document.getElementById("reviewerNameInput");
const reviewerPhoneInput = document.getElementById("reviewerPhoneInput");
const reviewerAccountInput = document.getElementById("reviewerAccountInput");
const reviewerPasswordInput = document.getElementById("reviewerPasswordInput");
const noticeModal = new bootstrap.Modal(document.getElementById("reviewerNoticeModal"));
const deleteModal = new bootstrap.Modal(document.getElementById("reviewerDeleteModal"));
const reviewerDeleteText = document.getElementById("reviewerDeleteText");
function escapeHtml(text) {
return String(text).replace(/[&<>"']/g, (char) => ({
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#39;"
})[char]);
}
function renderReviewerRow(reviewer, index) {
return (
'<tr data-index="' + index + '">' +
'<td>' + escapeHtml(reviewer.name) + '</td>' +
'<td>' + escapeHtml(reviewer.phone) + '</td>' +
'<td>' + escapeHtml(reviewer.account) + '</td>' +
'<td>' + escapeHtml(reviewer.password) + '</td>' +
'<td class="text-end reviewer-row-actions">' +
'<button type="button" class="btn btn-sm btn-outline-primary reviewer-edit-btn">修改</button>' +
'<button type="button" class="btn btn-sm btn-light border reviewer-remove-btn">删除</button>' +
'</td>' +
'</tr>'
);
}
function renderTrackTabs() {
trackTabs.innerHTML = tracks.map((track) => (
'<button type="button" class="reviewer-track-tab' + (track === currentTrack ? " active" : "") + '" data-track="' + escapeHtml(track) + '">' +
'<span class="reviewer-track-tab-name">' + escapeHtml(track) + '</span>' +
'<span class="reviewer-track-tab-count">' + reviewersByTrack[track].length + ' 人</span>' +
'</button>'
)).join("");
}
function renderPage() {
renderTrackTabs();
currentTrackTitle.textContent = currentTrack;
currentTrackMeta.textContent = "已配置 " + reviewersByTrack[currentTrack].length + " 名评审员";
tableBody.innerHTML = reviewersByTrack[currentTrack].map(renderReviewerRow).join("");
}
function openReviewerModal(index = null) {
editingIndex = index;
const reviewer = index === null
? { name: "", phone: "", account: "", password: "" }
: reviewersByTrack[currentTrack][index];
editTitle.textContent = index === null ? "新增评审员" : "修改评审员";
reviewerNameInput.value = reviewer.name || "";
reviewerPhoneInput.value = reviewer.phone || "";
reviewerAccountInput.value = reviewer.account || "";
reviewerPasswordInput.value = reviewer.password || "";
editForm.classList.remove("was-validated");
editModal.show();
}
trackTabs.addEventListener("click", (ev) => {
const tab = ev.target.closest(".reviewer-track-tab");
if (!tab) return;
currentTrack = tab.getAttribute("data-track");
renderPage();
});
document.getElementById("addReviewerBtn").addEventListener("click", () => {
openReviewerModal(null);
});
tableBody.addEventListener("click", (ev) => {
const editBtn = ev.target.closest(".reviewer-edit-btn");
if (editBtn) {
const row = editBtn.closest("tr");
openReviewerModal(Number(row.getAttribute("data-index")));
return;
}
const removeBtn = ev.target.closest(".reviewer-remove-btn");
if (removeBtn) {
const row = removeBtn.closest("tr");
const index = Number(row.getAttribute("data-index"));
const reviewer = reviewersByTrack[currentTrack][index];
pendingDeleteIndex = index;
reviewerDeleteText.textContent = "确定删除“" + reviewer.name + "”吗?";
deleteModal.show();
}
});
document.getElementById("reviewerDeleteConfirmBtn").addEventListener("click", () => {
if (pendingDeleteIndex === null) return;
reviewersByTrack[currentTrack].splice(pendingDeleteIndex, 1);
pendingDeleteIndex = null;
renderPage();
deleteModal.hide();
});
document.getElementById("reviewerEditConfirmBtn").addEventListener("click", () => {
editForm.classList.add("was-validated");
if (!editForm.checkValidity()) return;
const reviewer = {
name: reviewerNameInput.value.trim(),
phone: reviewerPhoneInput.value.trim(),
account: reviewerAccountInput.value.trim(),
password: reviewerPasswordInput.value.trim()
};
if (editingIndex === null) {
reviewersByTrack[currentTrack].push(reviewer);
} else {
reviewersByTrack[currentTrack][editingIndex] = reviewer;
}
renderPage();
editModal.hide();
noticeModal.show();
});
renderPage();
</script>
</body>
</html>