fenzhuo
This commit is contained in:
@@ -584,6 +584,11 @@
|
|||||||
<label for="enable_seating">开启分桌功能</label>
|
<label for="enable_seating">开启分桌功能</label>
|
||||||
</div>
|
</div>
|
||||||
<div id="seating_inputs">
|
<div id="seating_inputs">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>座位单位名称</label>
|
||||||
|
<input type="text" id="seat_unit_name" placeholder="如:桌、座位、区、组" style="width: 200px;">
|
||||||
|
<p style="font-size: 0.8em; color: var(--text-muted); margin-top: 5px;">显示在座位号旁边的单位,如"桌"、"座位"、"区"等</p>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>总桌数</label>
|
<label>总桌数</label>
|
||||||
<input type="number" id="total_tables" min="1">
|
<input type="number" id="total_tables" min="1">
|
||||||
@@ -819,6 +824,22 @@
|
|||||||
<img id="image_preview" class="preview-img" src="">
|
<img id="image_preview" class="preview-img" src="">
|
||||||
</div>
|
</div>
|
||||||
<button onclick="uploadImage()">上传图片</button>
|
<button onclick="uploadImage()">上传图片</button>
|
||||||
|
|
||||||
|
<hr style="border-color: rgba(0,242,255,0.2); margin: 25px 0;">
|
||||||
|
|
||||||
|
<div class="checkbox-wrapper" style="margin-bottom: 15px;">
|
||||||
|
<input type="checkbox" id="enable_qrcode">
|
||||||
|
<label for="enable_qrcode">显示入群二维码(签到成功后将展示)</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>入群二维码图片</label>
|
||||||
|
<input type="file" id="qrcode_image_file" accept="image/*" style="padding: 10px 0;">
|
||||||
|
<img id="qrcode_preview" class="preview-img" src="" style="max-width: 200px;">
|
||||||
|
</div>
|
||||||
|
<button onclick="uploadQrcode()">上传二维码</button>
|
||||||
|
<p style="font-size: 0.85em; color: var(--text-muted); margin-top: 10px;">
|
||||||
|
💡 开启后,签到成功页面将显示二维码,长按可保存图片
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -863,6 +884,13 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
checkAuthStatus();
|
checkAuthStatus();
|
||||||
|
|
||||||
|
const seatUnitInput = document.getElementById('seat_unit_name');
|
||||||
|
if (seatUnitInput) {
|
||||||
|
seatUnitInput.addEventListener('input', function() {
|
||||||
|
updateSeatingLabels(this.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function checkAuthStatus() {
|
async function checkAuthStatus() {
|
||||||
@@ -948,6 +976,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据座位单位名称更新标签文字
|
||||||
|
*/
|
||||||
|
function updateSeatingLabels(unitName) {
|
||||||
|
const unit = unitName || '桌';
|
||||||
|
const labels = document.querySelectorAll('#seating_inputs .form-group label');
|
||||||
|
if (labels.length >= 2) {
|
||||||
|
labels[1].textContent = `总${unit}数`;
|
||||||
|
labels[2].textContent = `每${unit}最大人数`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load config on startup
|
// Load config on startup
|
||||||
fetch('/api/admin/config')
|
fetch('/api/admin/config')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
@@ -962,6 +1002,9 @@
|
|||||||
document.getElementById('bg_color').value = config.bg_color;
|
document.getElementById('bg_color').value = config.bg_color;
|
||||||
document.getElementById('image_preview').src = config.header_image;
|
document.getElementById('image_preview').src = config.header_image;
|
||||||
|
|
||||||
|
document.getElementById('enable_qrcode').checked = config.enable_qrcode === true;
|
||||||
|
document.getElementById('qrcode_preview').src = config.qrcode_image || '';
|
||||||
|
|
||||||
// Checkin Config
|
// Checkin Config
|
||||||
document.getElementById('enable_ticket_validation').checked = config.enable_ticket_validation !== false;
|
document.getElementById('enable_ticket_validation').checked = config.enable_ticket_validation !== false;
|
||||||
document.getElementById('enable_sms_verification').checked = config.enable_sms_verification === true;
|
document.getElementById('enable_sms_verification').checked = config.enable_sms_verification === true;
|
||||||
@@ -982,6 +1025,8 @@
|
|||||||
document.getElementById('enable_seating').checked = config.enable_seating !== false; // Default true
|
document.getElementById('enable_seating').checked = config.enable_seating !== false; // Default true
|
||||||
document.getElementById('total_tables').value = config.total_tables || 14;
|
document.getElementById('total_tables').value = config.total_tables || 14;
|
||||||
document.getElementById('max_per_table').value = config.max_per_table || 10;
|
document.getElementById('max_per_table').value = config.max_per_table || 10;
|
||||||
|
document.getElementById('seat_unit_name').value = config.seat_unit_name || '桌';
|
||||||
|
updateSeatingLabels(config.seat_unit_name);
|
||||||
toggleSeatingInputs();
|
toggleSeatingInputs();
|
||||||
|
|
||||||
// Field Configs - 使用新版渲染函数
|
// Field Configs - 使用新版渲染函数
|
||||||
@@ -1467,6 +1512,9 @@
|
|||||||
bg_color: document.getElementById('bg_color').value,
|
bg_color: document.getElementById('bg_color').value,
|
||||||
header_image: document.getElementById('image_preview').src.replace(window.location.origin, ''),
|
header_image: document.getElementById('image_preview').src.replace(window.location.origin, ''),
|
||||||
|
|
||||||
|
enable_qrcode: document.getElementById('enable_qrcode').checked,
|
||||||
|
qrcode_image: document.getElementById('qrcode_preview').src.replace(window.location.origin, ''),
|
||||||
|
|
||||||
// Checkin Config
|
// Checkin Config
|
||||||
enable_ticket_validation: document.getElementById('enable_ticket_validation').checked,
|
enable_ticket_validation: document.getElementById('enable_ticket_validation').checked,
|
||||||
enable_sms_verification: document.getElementById('enable_sms_verification').checked,
|
enable_sms_verification: document.getElementById('enable_sms_verification').checked,
|
||||||
@@ -1485,6 +1533,7 @@
|
|||||||
|
|
||||||
// Seating Config
|
// Seating Config
|
||||||
enable_seating: document.getElementById('enable_seating').checked,
|
enable_seating: document.getElementById('enable_seating').checked,
|
||||||
|
seat_unit_name: document.getElementById('seat_unit_name').value || '桌',
|
||||||
total_tables: parseInt(document.getElementById('total_tables').value),
|
total_tables: parseInt(document.getElementById('total_tables').value),
|
||||||
max_per_table: parseInt(document.getElementById('max_per_table').value),
|
max_per_table: parseInt(document.getElementById('max_per_table').value),
|
||||||
|
|
||||||
@@ -1583,6 +1632,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传入群二维码图片
|
||||||
|
*/
|
||||||
|
async function uploadQrcode() {
|
||||||
|
const fileInput = document.getElementById('qrcode_image_file');
|
||||||
|
if (!fileInput.files[0]) {
|
||||||
|
showMessage('请先选择图片', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', fileInput.files[0]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/admin/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if (res.ok) {
|
||||||
|
document.getElementById('qrcode_preview').src = data.url;
|
||||||
|
showMessage('二维码上传成功,请记得点击保存设置', 'success');
|
||||||
|
} else {
|
||||||
|
showMessage('上传失败: ' + data.message, 'error');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
showMessage('网络错误', 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function initDatabase() {
|
async function initDatabase() {
|
||||||
if (!confirm('确定要在当前配置的数据库中初始化/迁移表结构吗?\n(此操作安全,不会删除现有数据)')) return;
|
if (!confirm('确定要在当前配置的数据库中初始化/迁移表结构吗?\n(此操作安全,不会删除现有数据)')) return;
|
||||||
|
|
||||||
|
|||||||
@@ -463,6 +463,45 @@
|
|||||||
100% { box-shadow: 0 0 0 0 rgba(255, 0, 0, 0); }
|
100% { box-shadow: 0 0 0 0 rgba(255, 0, 0, 0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 入群二维码样式 */
|
||||||
|
.qrcode-section {
|
||||||
|
margin-top: 25px;
|
||||||
|
padding: 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid rgba(0, 242, 255, 0.3);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-title {
|
||||||
|
color: var(--primary-color);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-image {
|
||||||
|
max-width: 180px;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(0, 242, 255, 0.4);
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-image:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 6px 20px rgba(0, 242, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-hint {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-top: 10px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -576,6 +615,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="qrcode-container-success" class="qrcode-section hidden">
|
||||||
|
<p class="qrcode-title">📱 扫码加入社群</p>
|
||||||
|
<img id="qrcode-img-success" class="qrcode-image" src="" alt="入群二维码" oncontextmenu="handleQrcodeLongPress(event)">
|
||||||
|
<p class="qrcode-hint">长按二维码保存到相册</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p style="margin-top: 20px;">请入座等待会议开始</p>
|
<p style="margin-top: 20px;">请入座等待会议开始</p>
|
||||||
<button id="success-btn" onclick="window.location.href='/wall'" style="margin-top: 30px; background: transparent; border: 1px solid rgba(255,255,255,0.2);">前往活动</button>
|
<button id="success-btn" onclick="window.location.href='/wall'" style="margin-top: 30px; background: transparent; border: 1px solid rgba(255,255,255,0.2);">前往活动</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -601,6 +646,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="qrcode-container-signed" class="qrcode-section hidden">
|
||||||
|
<p class="qrcode-title">📱 扫码加入社群</p>
|
||||||
|
<img id="qrcode-img-signed" class="qrcode-image" src="" alt="入群二维码" oncontextmenu="handleQrcodeLongPress(event)">
|
||||||
|
<p class="qrcode-hint">长按二维码保存到相册</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p style="margin-top: 20px;">请入座等待会议开始</p>
|
<p style="margin-top: 20px;">请入座等待会议开始</p>
|
||||||
<button id="signed-btn" onclick="window.location.href='/wall'" style="margin-top: 30px; background: transparent; border: 1px solid rgba(255,255,255,0.2);">前往活动</button>
|
<button id="signed-btn" onclick="window.location.href='/wall'" style="margin-top: 30px; background: transparent; border: 1px solid rgba(255,255,255,0.2);">前往活动</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -646,6 +697,25 @@
|
|||||||
|
|
||||||
let isCheckinCodeVerified = false;
|
let isCheckinCodeVerified = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取座位单位名称
|
||||||
|
*/
|
||||||
|
function getSeatUnitName() {
|
||||||
|
return CONFIG.seat_unit_name || '桌';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化座位号显示(替换"桌"为单位名称)
|
||||||
|
* @param {string} seatText 原始座位文字
|
||||||
|
* @returns {string} 格式化后的座位文字
|
||||||
|
*/
|
||||||
|
function formatSeatDisplay(seatText) {
|
||||||
|
if (!seatText) return '';
|
||||||
|
const unit = getSeatUnitName();
|
||||||
|
if (unit === '桌') return seatText;
|
||||||
|
return seatText.replace(/桌/g, unit);
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshConfig() {
|
async function refreshConfig() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/admin/config');
|
const res = await fetch('/api/admin/config');
|
||||||
@@ -844,7 +914,7 @@
|
|||||||
document.getElementById('signed-phone').textContent = data.user.phone;
|
document.getElementById('signed-phone').textContent = data.user.phone;
|
||||||
|
|
||||||
if (CONFIG.enable_seating !== false) {
|
if (CONFIG.enable_seating !== false) {
|
||||||
document.getElementById('signed-seat-display').textContent = data.seat || "自由席";
|
document.getElementById('signed-seat-display').textContent = formatSeatDisplay(data.seat) || ("自由" + getSeatUnitName());
|
||||||
document.getElementById('signed-seat-display').style.display = 'block';
|
document.getElementById('signed-seat-display').style.display = 'block';
|
||||||
document.getElementById('signed-seat-label').textContent = "您的座位是";
|
document.getElementById('signed-seat-label').textContent = "您的座位是";
|
||||||
document.getElementById('signed-seat-label').style.display = 'block';
|
document.getElementById('signed-seat-label').style.display = 'block';
|
||||||
@@ -860,6 +930,9 @@
|
|||||||
document.getElementById('signed-seat-label').textContent = "签到成功,请自由入座";
|
document.getElementById('signed-seat-label').textContent = "签到成功,请自由入座";
|
||||||
document.getElementById('signed-tablemates-container').classList.add('hidden');
|
document.getElementById('signed-tablemates-container').classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 显示二维码(如果配置开启)
|
||||||
|
updateQrcodeDisplay();
|
||||||
} else {
|
} else {
|
||||||
// Single user found
|
// Single user found
|
||||||
await refreshConfig();
|
await refreshConfig();
|
||||||
@@ -968,7 +1041,7 @@
|
|||||||
document.getElementById('success-btn').textContent = payload.name + '/点击进入活动大厅';
|
document.getElementById('success-btn').textContent = payload.name + '/点击进入活动大厅';
|
||||||
if (CONFIG.enable_seating !== false) {
|
if (CONFIG.enable_seating !== false) {
|
||||||
// Show assigned seat
|
// Show assigned seat
|
||||||
document.getElementById('seat-display').textContent = data.seat || "自由席";
|
document.getElementById('seat-display').textContent = formatSeatDisplay(data.seat) || ("自由" + getSeatUnitName());
|
||||||
document.getElementById('seat-display').style.display = 'block';
|
document.getElementById('seat-display').style.display = 'block';
|
||||||
document.getElementById('success-seat-label').textContent = "您的座位已分配";
|
document.getElementById('success-seat-label').textContent = "您的座位已分配";
|
||||||
document.getElementById('success-seat-label').style.display = 'block';
|
document.getElementById('success-seat-label').style.display = 'block';
|
||||||
@@ -985,6 +1058,9 @@
|
|||||||
document.getElementById('tablemates-container').classList.add('hidden');
|
document.getElementById('tablemates-container').classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 显示二维码(如果配置开启)
|
||||||
|
updateQrcodeDisplay();
|
||||||
|
|
||||||
document.getElementById('step-form').classList.add('hidden');
|
document.getElementById('step-form').classList.add('hidden');
|
||||||
document.getElementById('step-success').classList.remove('hidden');
|
document.getElementById('step-success').classList.remove('hidden');
|
||||||
} else {
|
} else {
|
||||||
@@ -1061,6 +1137,49 @@
|
|||||||
updateCheckinButtonState();
|
updateCheckinButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据配置控制二维码显示
|
||||||
|
*/
|
||||||
|
function updateQrcodeDisplay() {
|
||||||
|
const enableQrcode = CONFIG.enable_qrcode === true;
|
||||||
|
const qrcodeImage = CONFIG.qrcode_image;
|
||||||
|
|
||||||
|
if (enableQrcode && qrcodeImage) {
|
||||||
|
// 签到成功页面的二维码
|
||||||
|
const successContainer = document.getElementById('qrcode-container-success');
|
||||||
|
const successImg = document.getElementById('qrcode-img-success');
|
||||||
|
if (successContainer) {
|
||||||
|
successImg.src = qrcodeImage;
|
||||||
|
successContainer.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已签到页面的二维码
|
||||||
|
const signedContainer = document.getElementById('qrcode-container-signed');
|
||||||
|
const signedImg = document.getElementById('qrcode-img-signed');
|
||||||
|
if (signedContainer) {
|
||||||
|
signedImg.src = qrcodeImage;
|
||||||
|
signedContainer.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.getElementById('qrcode-container-success')?.classList.add('hidden');
|
||||||
|
document.getElementById('qrcode-container-signed')?.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理二维码长按保存(在 PC 端右键保存)
|
||||||
|
*/
|
||||||
|
function handleQrcodeLongPress(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const img = event.target;
|
||||||
|
if (img.src) {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = img.src;
|
||||||
|
link.download = '入群二维码';
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function sendCheckinSms() {
|
async function sendCheckinSms() {
|
||||||
const phone = document.getElementById('form-phone').value.trim();
|
const phone = document.getElementById('form-phone').value.trim();
|
||||||
const errorDiv = document.getElementById('submit-error');
|
const errorDiv = document.getElementById('submit-error');
|
||||||
|
|||||||
Reference in New Issue
Block a user