- server.js: fix getSiteName() returning string when not installed causing 'getSiteName(...).then is not a function' crash on homepage (deploy blocker) - server.js: auto-load business routes after install completes (no restart needed), HTML cache keyed by api_key - install: validate db name/email/password, trigger route loading after complete - app.js: fix forgot/reset/verify pages rendering HomePage (missing page mapping) - verify.js: support URL token auto-verification for external registration links - auth: new email_code template for 6-digit code, reset_password template (forgot-password was using verify_email template) - upload.js: fix MP4 magic-bytes check using undefined buf variable - tickets.js: status enum validation, anonymous submission rate limit - security.js: XSS whitelist preserves email template HTML, strips scripts, blocks javascript:/data: hrefs; CORS reject returns 403 - bans.js: allow clearing reason/duration, status enum validation - users.js: fix req.user.role ReferenceError in create user modal - home.js: tracking results now have detail view button - .gitignore: ignore data/ (db credentials), logs, session files, temp scripts
111 lines
5.7 KiB
JavaScript
111 lines
5.7 KiB
JavaScript
const InstallPage = {
|
||
step: 1,
|
||
|
||
async render() {
|
||
const status = await API.get('/install/status');
|
||
if (status.installed) { location.hash = '#/login'; return ''; }
|
||
return `<div style="max-width:600px;margin:0 auto;padding:30px 0"><div id="install-steps"></div></div>`;
|
||
},
|
||
|
||
mount() {
|
||
this.showStep(1);
|
||
},
|
||
|
||
showStep(n) {
|
||
this.step = n;
|
||
const ct = document.getElementById('install-steps');
|
||
if (n === 1) this.renderDBStep(ct);
|
||
else if (n === 2) this.renderAdminStep(ct);
|
||
},
|
||
|
||
renderDBStep(ct) {
|
||
ct.innerHTML = `
|
||
<div class="card"><div class="card-h"><i class="fas fa-database"></i> 第1步:数据库配置</div><div class="card-b">
|
||
<form id="install-db">
|
||
<div class="grid-2"><div class="form-group"><label>MySQL 主机</label><input id="db-host" value="localhost"></div>
|
||
<div class="form-group"><label>端口</label><input id="db-port" value="3306" type="number"></div></div>
|
||
<div class="grid-2"><div class="form-group"><label>用户名</label><input id="db-user" value="root" required></div>
|
||
<div class="form-group"><label>密码</label><input type="password" id="db-pass"></div></div>
|
||
<div class="form-group"><label>数据库名</label><input id="db-name" value="mc_report" required><span class="help">如不存在将自动创建</span></div>
|
||
<div id="db-err" class="alert alert-e hidden"></div>
|
||
<button type="submit" class="btn btn-p"><i class="fas fa-check"></i> 测试连接并继续</button>
|
||
</form>
|
||
</div></div>
|
||
`;
|
||
document.getElementById('install-db').onsubmit = async e => {
|
||
e.preventDefault();
|
||
const btn = e.target.querySelector('button');
|
||
btn.disabled = true;
|
||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 测试中...';
|
||
try {
|
||
await API.post('/install/check-db', {
|
||
host: document.getElementById('db-host').value,
|
||
port: document.getElementById('db-port').value,
|
||
user: document.getElementById('db-user').value,
|
||
password: document.getElementById('db-pass').value,
|
||
database: document.getElementById('db-name').value,
|
||
});
|
||
this.dbConfig = {
|
||
host: document.getElementById('db-host').value,
|
||
port: document.getElementById('db-port').value,
|
||
user: document.getElementById('db-user').value,
|
||
pass: document.getElementById('db-pass').value,
|
||
name: document.getElementById('db-name').value,
|
||
};
|
||
this.showStep(2);
|
||
} catch (ex) {
|
||
document.getElementById('db-err').textContent = ex.message;
|
||
document.getElementById('db-err').classList.remove('hidden');
|
||
btn.disabled = false;
|
||
btn.innerHTML = '<i class="fas fa-check"></i> 测试连接并继续';
|
||
}
|
||
};
|
||
},
|
||
|
||
renderAdminStep(ct) {
|
||
ct.innerHTML = `
|
||
<div class="card"><div class="card-h"><i class="fas fa-user-crown"></i> 第2步:创建服主账号</div><div class="card-b">
|
||
<form id="install-admin">
|
||
<div class="grid-2"><div class="form-group"><label>站点名称</label><input id="ia-sitename" value="MC举报系统"></div>
|
||
<div class="form-group"><label>站点地址</label><input id="ia-siteurl" value="${location.origin}"></div></div>
|
||
<div class="grid-2"><div class="form-group"><label>服主用户名 *</label><input id="ia-username" required placeholder="登录用"></div>
|
||
<div class="form-group"><label>邮箱 *</label><input type="email" id="ia-email" required></div></div>
|
||
<div class="grid-2"><div class="form-group"><label>密码 *</label><input type="password" id="ia-password" required minlength="6"></div>
|
||
<div class="form-group"><label>游戏名称</label><input id="ia-game" placeholder="Minecraft ID"></div></div>
|
||
<div class="form-group"><label>游戏UID</label><input id="ia-uid" placeholder="游戏唯一ID"></div>
|
||
<div id="ia-err" class="alert alert-e hidden"></div>
|
||
<div id="ia-warn" class="alert alert-i"><strong>注意:</strong>安装完成后需要重启服务器才能加载业务路由。请记好账号密码。</div>
|
||
<button type="submit" class="btn btn-p btn-lg w-full"><i class="fas fa-check"></i> 完成安装</button>
|
||
</form>
|
||
</div></div>
|
||
`;
|
||
document.getElementById('install-admin').onsubmit = async e => {
|
||
e.preventDefault();
|
||
const btn = e.target.querySelector('button');
|
||
btn.disabled = true;
|
||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 安装中...';
|
||
try {
|
||
await API.post('/install/complete', {
|
||
...this.dbConfig,
|
||
db_host: this.dbConfig.host, db_port: this.dbConfig.port,
|
||
db_user: this.dbConfig.user, db_pass: this.dbConfig.pass, db_name: this.dbConfig.name,
|
||
site_name: document.getElementById('ia-sitename').value,
|
||
site_url: document.getElementById('ia-siteurl').value,
|
||
admin_username: document.getElementById('ia-username').value,
|
||
admin_password: document.getElementById('ia-password').value,
|
||
admin_email: document.getElementById('ia-email').value,
|
||
admin_game_name: document.getElementById('ia-game').value,
|
||
admin_game_uid: document.getElementById('ia-uid').value,
|
||
});
|
||
document.getElementById('install-admin').innerHTML = '<div class="alert alert-s"><h3><i class="fas fa-check-circle"></i> 安装成功!</h3><p>系统已就绪,正在跳转登录...</p></div>';
|
||
setTimeout(() => location.hash = '#/login', 1500);
|
||
} catch (ex) {
|
||
document.getElementById('ia-err').textContent = ex.message;
|
||
document.getElementById('ia-err').classList.remove('hidden');
|
||
btn.disabled = false;
|
||
btn.innerHTML = '<i class="fas fa-check"></i> 完成安装';
|
||
}
|
||
};
|
||
}
|
||
};
|