265 lines
8.2 KiB
JavaScript
265 lines
8.2 KiB
JavaScript
// 后台管理JavaScript - 支持服务器和本地双模式
|
||
|
||
// 状态管理
|
||
let isLoggedIn = sessionStorage.getItem('isAdminLoggedIn') === 'true';
|
||
let authToken = sessionStorage.getItem('authToken') || '';
|
||
|
||
// DOM元素
|
||
const loginSection = document.getElementById('loginSection');
|
||
const adminPanel = document.getElementById('adminPanel');
|
||
const loginForm = document.getElementById('loginForm');
|
||
const logoutBtn = document.getElementById('logoutBtn');
|
||
const createListForm = document.getElementById('createListForm');
|
||
const rollCallListsDiv = document.getElementById('rollCallLists');
|
||
const rollCallRecordsDiv = document.getElementById('rollCallRecords');
|
||
const qrModal = document.getElementById('qrModal');
|
||
const qrCodeDiv = document.getElementById('qrCode');
|
||
const rollCallCodeSpan = document.getElementById('rollCallCode');
|
||
|
||
// QRCode实例
|
||
const qrCode = new SimpleQRCode();
|
||
|
||
// 初始化
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
// 显示运行模式
|
||
const modeText = dataStorage.isServerMode ? '服务器模式' : '本地模式';
|
||
const modeIndicator = document.getElementById('modeIndicator');
|
||
|
||
if (modeIndicator) {
|
||
modeIndicator.textContent = `当前运行模式: ${modeText}`;
|
||
if (!dataStorage.isServerMode) {
|
||
modeIndicator.textContent += ' (数据保存在浏览器本地)';
|
||
}
|
||
}
|
||
|
||
console.log(`点名系统运行在: ${modeText}`);
|
||
|
||
if (isLoggedIn) {
|
||
showAdminPanel();
|
||
loadLists();
|
||
loadRecords();
|
||
}
|
||
});
|
||
|
||
// 登录
|
||
loginForm.addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
const username = document.getElementById('username').value;
|
||
const password = document.getElementById('password').value;
|
||
|
||
try {
|
||
const result = await dataStorage.login(username, password);
|
||
|
||
isLoggedIn = true;
|
||
authToken = result.token;
|
||
sessionStorage.setItem('isAdminLoggedIn', 'true');
|
||
sessionStorage.setItem('authToken', authToken);
|
||
|
||
showAdminPanel();
|
||
await loadLists();
|
||
await loadRecords();
|
||
} catch (error) {
|
||
alert('登录失败:' + error.message);
|
||
}
|
||
});
|
||
|
||
// 退出登录
|
||
logoutBtn.addEventListener('click', () => {
|
||
isLoggedIn = false;
|
||
authToken = '';
|
||
sessionStorage.removeItem('isAdminLoggedIn');
|
||
sessionStorage.removeItem('authToken');
|
||
loginSection.style.display = 'block';
|
||
adminPanel.style.display = 'none';
|
||
});
|
||
|
||
// 显示管理面板
|
||
function showAdminPanel() {
|
||
loginSection.style.display = 'none';
|
||
adminPanel.style.display = 'block';
|
||
}
|
||
|
||
// 加载点名列表
|
||
async function loadLists() {
|
||
try {
|
||
const lists = await dataStorage.getLists();
|
||
renderLists(lists);
|
||
} catch (error) {
|
||
console.error('加载列表失败:', error);
|
||
rollCallListsDiv.innerHTML = '<p style="color: red;">加载失败:' + error.message + '</p>';
|
||
}
|
||
}
|
||
|
||
// 加载点名记录
|
||
async function loadRecords() {
|
||
try {
|
||
const records = await dataStorage.getRecords();
|
||
renderRecords(records);
|
||
} catch (error) {
|
||
console.error('加载记录失败:', error);
|
||
rollCallRecordsDiv.innerHTML = '<p style="color: red;">加载失败:' + error.message + '</p>';
|
||
}
|
||
}
|
||
|
||
// 创建点名名单
|
||
createListForm.addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
const listName = document.getElementById('listName').value;
|
||
const memberListText = document.getElementById('memberList').value;
|
||
const members = memberListText.split('\n').filter(name => name.trim() !== '').map(name => name.trim());
|
||
|
||
try {
|
||
const newList = await dataStorage.createList(listName, members);
|
||
|
||
// 清空表单
|
||
createListForm.reset();
|
||
|
||
// 重新加载列表
|
||
await loadLists();
|
||
|
||
// 显示二维码
|
||
showQRCode(newList);
|
||
} catch (error) {
|
||
alert('创建失败:' + error.message);
|
||
}
|
||
});
|
||
|
||
// 显示二维码
|
||
function showQRCode(list) {
|
||
qrModal.style.display = 'block';
|
||
rollCallCodeSpan.textContent = list.code;
|
||
|
||
// 生成二维码URL
|
||
let url;
|
||
if (dataStorage.isServerMode) {
|
||
// 服务器模式:使用当前域名
|
||
url = `${window.location.origin}${window.location.pathname.replace('admin.html', 'index.html')}?code=${list.code}`;
|
||
} else {
|
||
// 本地模式:使用相对路径
|
||
url = `index.html?code=${list.code}`;
|
||
}
|
||
|
||
qrCodeDiv.innerHTML = '';
|
||
|
||
// 创建canvas元素
|
||
const canvas = document.createElement('canvas');
|
||
qrCodeDiv.appendChild(canvas);
|
||
|
||
// 使用本地QRCode生成器
|
||
try {
|
||
qrCode.toCanvas(canvas, url, {
|
||
width: 200,
|
||
margin: 2
|
||
});
|
||
} catch (error) {
|
||
console.error('二维码生成错误:', error);
|
||
qrCodeDiv.innerHTML = '<p style="color: red;">二维码生成失败</p>';
|
||
}
|
||
}
|
||
|
||
// 关闭弹窗
|
||
document.querySelector('.close').addEventListener('click', () => {
|
||
qrModal.style.display = 'none';
|
||
});
|
||
|
||
window.addEventListener('click', (e) => {
|
||
if (e.target === qrModal) {
|
||
qrModal.style.display = 'none';
|
||
}
|
||
});
|
||
|
||
// 渲染点名列表
|
||
function renderLists(lists) {
|
||
if (!lists || lists.length === 0) {
|
||
rollCallListsDiv.innerHTML = '<p>暂无点名列表</p>';
|
||
return;
|
||
}
|
||
|
||
rollCallListsDiv.innerHTML = lists.map(list => `
|
||
<div class="list-item">
|
||
<div class="list-item-header">
|
||
<span class="list-item-title">${list.name}</span>
|
||
<span class="list-item-code">编号:${list.code}</span>
|
||
</div>
|
||
<p>创建时间:${list.createdAt}</p>
|
||
<p>成员数:${list.members.length} | 已点名:${list.members.filter(m => m.completed).length}</p>
|
||
<div class="list-item-actions">
|
||
<button class="btn btn-primary" onclick="showQRCodeById(${list.id})">查看二维码</button>
|
||
<button class="btn btn-secondary" onclick="editList(${list.id})">编辑</button>
|
||
<button class="btn btn-danger" onclick="deleteList(${list.id})">删除</button>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// 显示二维码(通过ID)
|
||
async function showQRCodeById(id) {
|
||
try {
|
||
const lists = await dataStorage.getLists();
|
||
const list = lists.find(l => l.id === id);
|
||
if (list) {
|
||
showQRCode(list);
|
||
}
|
||
} catch (error) {
|
||
alert('获取列表失败:' + error.message);
|
||
}
|
||
}
|
||
|
||
// 编辑名单
|
||
async function editList(id) {
|
||
try {
|
||
const lists = await dataStorage.getLists();
|
||
const list = lists.find(l => l.id === id);
|
||
if (!list) return;
|
||
|
||
const newName = prompt('请输入新的名单名称:', list.name);
|
||
if (newName === null) return;
|
||
|
||
const newMembersText = prompt('请输入新的名单成员(每行一个姓名):', list.members.map(m => m.name).join('\n'));
|
||
if (newMembersText === null) return;
|
||
|
||
const newMembers = newMembersText.split('\n').filter(name => name.trim() !== '').map(name => name.trim());
|
||
|
||
await dataStorage.updateList(id, newName, newMembers);
|
||
await loadLists();
|
||
} catch (error) {
|
||
alert('编辑失败:' + error.message);
|
||
}
|
||
}
|
||
|
||
// 删除名单
|
||
async function deleteList(id) {
|
||
if (confirm('确定要删除这个点名名单吗?')) {
|
||
try {
|
||
await dataStorage.deleteList(id);
|
||
await loadLists();
|
||
} catch (error) {
|
||
alert('删除失败:' + error.message);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 渲染点名记录
|
||
function renderRecords(records) {
|
||
if (!records || records.length === 0) {
|
||
rollCallRecordsDiv.innerHTML = '<p>暂无点名记录</p>';
|
||
return;
|
||
}
|
||
|
||
rollCallRecordsDiv.innerHTML = records.map(record => `
|
||
<div class="record-item">
|
||
<div class="record-header">
|
||
<span class="record-name">${record.name}</span>
|
||
<span class="record-time">${record.timestamp}</span>
|
||
</div>
|
||
<p>名单:${record.listName}</p>
|
||
<p>编号:${record.code}</p>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// 暴露函数到全局
|
||
window.showQRCodeById = showQRCodeById;
|
||
window.editList = editList;
|
||
window.deleteList = deleteList;
|