205 lines
10 KiB
HTML
205 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>系统安装向导</title>
|
|
<style>
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body { font-family: system-ui, -apple-system, "Microsoft YaHei", sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; }
|
|
.wrap { width: 100%; max-width: 620px; background: #fff; border-radius: 14px; box-shadow: 0 15px 40px rgba(0,0,0,.2); overflow: hidden; }
|
|
.hd { background: linear-gradient(135deg, #667eea, #764ba2); color: #fff; padding: 26px 30px; }
|
|
.hd h1 { font-size: 22px; font-weight: 600; }
|
|
.hd p { margin-top: 6px; opacity: .85; font-size: 13px; }
|
|
.steps { display: flex; padding: 16px 30px 0; gap: 8px; }
|
|
.step { flex: 1; text-align: center; font-size: 12px; color: #aaa; padding-bottom: 10px; border-bottom: 2px solid #eee; }
|
|
.step.active { color: #667eea; border-color: #667eea; font-weight: 600; }
|
|
.step.done { color: #2ecc71; border-color: #2ecc71; }
|
|
.bd { padding: 24px 30px 30px; }
|
|
.panel { display: none; }
|
|
.panel.show { display: block; }
|
|
.env-item { display: flex; justify-content: space-between; padding: 9px 0; border-bottom: 1px dashed #eee; font-size: 14px; }
|
|
.env-item .st { font-weight: 600; }
|
|
.ok { color: #2ecc71; } .bad { color: #e74c3c; }
|
|
label { display: block; font-size: 13px; color: #555; margin: 14px 0 6px; }
|
|
input { width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; outline: none; transition: border .2s; }
|
|
input:focus { border-color: #667eea; }
|
|
.row { display: flex; gap: 12px; }
|
|
.row > div { flex: 1; }
|
|
.btn { display: inline-block; margin-top: 22px; padding: 11px 26px; background: linear-gradient(135deg, #667eea, #764ba2); color: #fff; border: none; border-radius: 8px; font-size: 15px; cursor: pointer; transition: opacity .2s; }
|
|
.btn:hover { opacity: .9; }
|
|
.btn:disabled { background: #ccc; cursor: not-allowed; }
|
|
.msg { margin-top: 16px; padding: 12px 14px; border-radius: 8px; font-size: 14px; display: none; }
|
|
.msg.info { background: #eef4ff; color: #3b6fd4; display: block; }
|
|
.msg.err { background: #fdecea; color: #e74c3c; display: block; }
|
|
.msg.succ { background: #eafaf1; color: #27ae60; display: block; }
|
|
.hint { font-size: 12px; color: #999; margin-top: 4px; }
|
|
code { background: #f4f4f6; padding: 1px 5px; border-radius: 4px; font-size: 12px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="wrap">
|
|
<div class="hd">
|
|
<h1>系统安装向导</h1>
|
|
<p>请按步骤完成数据库配置与初始化</p>
|
|
</div>
|
|
<div class="steps">
|
|
<div class="step active" id="s1">1. 环境检测</div>
|
|
<div class="step" id="s2">2. 数据库配置</div>
|
|
<div class="step" id="s3">3. 执行安装</div>
|
|
<div class="step" id="s4">4. 完成</div>
|
|
</div>
|
|
<div class="bd">
|
|
<!-- 步骤1 -->
|
|
<div class="panel show" id="p1">
|
|
<div id="envList"><div class="hint">正在检测运行环境…</div></div>
|
|
<button class="btn" id="toStep2" disabled>下一步</button>
|
|
</div>
|
|
<!-- 步骤2 -->
|
|
<div class="panel" id="p2">
|
|
<label>数据库主机</label>
|
|
<input name="db_host" value="127.0.0.1">
|
|
<div class="row">
|
|
<div>
|
|
<label>端口</label>
|
|
<input name="db_port" value="3306">
|
|
</div>
|
|
<div>
|
|
<label>字符集</label>
|
|
<input name="db_charset" value="utf8mb4">
|
|
</div>
|
|
</div>
|
|
<label>数据库名</label>
|
|
<input name="db_name" placeholder="如 ywxapp">
|
|
<label>数据库用户名</label>
|
|
<input name="db_user" placeholder="如 root">
|
|
<label>数据库密码</label>
|
|
<input name="db_pass" type="password" placeholder="建议不含 # = ; 等特殊字符">
|
|
<label>表前缀</label>
|
|
<input name="db_prefix" value="wxapp_">
|
|
<div class="hint">若数据库不存在,向导将自动创建;密码请避免 <code>#</code> <code>=</code> <code>;</code> 等特殊字符。</div>
|
|
|
|
<div style="margin-top:18px;padding-top:14px;border-top:1px dashed #eee">
|
|
<div style="font-size:13px;color:#667eea;font-weight:600;margin-bottom:4px">管理员账号</div>
|
|
<div class="hint" style="margin-bottom:8px">该账号用于登录系统后台,请牢记。</div>
|
|
<label>管理员账号</label>
|
|
<input name="admin_account" value="admin" placeholder="如 admin">
|
|
<label>管理员密码</label>
|
|
<input name="admin_password" type="password" placeholder="设置后台登录密码">
|
|
<label>管理员昵称</label>
|
|
<input name="admin_nickname" value="超级管理员" placeholder="如 超级管理员">
|
|
<div class="row">
|
|
<div>
|
|
<label>管理员邮箱</label>
|
|
<input name="admin_email" placeholder="可选">
|
|
</div>
|
|
<div>
|
|
<label>管理员手机</label>
|
|
<input name="admin_mobile" placeholder="可选">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button class="btn" id="testDb">测试连接</button>
|
|
<button class="btn" id="toStep3" style="background:#2ecc71">开始安装</button>
|
|
<div class="msg" id="dbMsg"></div>
|
|
</div>
|
|
<!-- 步骤3 -->
|
|
<div class="panel" id="p3">
|
|
<div class="msg info" id="installMsg">正在导入数据库结构与初始数据,请稍候…</div>
|
|
</div>
|
|
<!-- 步骤4 -->
|
|
<div class="panel" id="p4">
|
|
<div class="msg succ">🎉 安装完成!</div>
|
|
<p style="margin-top:14px;font-size:14px;color:#555;line-height:1.7">
|
|
数据库已初始化,配置文件 <code>.env</code> 已写入,安装锁 <code>install.lock</code> 已生成。<br>
|
|
现在可以访问前台/后台开始使用。<br><br>
|
|
<b>安全提示:</b>生产环境部署完成后,建议删除 <code>public/install/</code> 目录与 <code>public/tools/</code> 目录,避免被重复安装。
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function setStep(n) {
|
|
for (var i = 1; i <= 4; i++) {
|
|
document.getElementById('p' + i).classList.toggle('show', i === n);
|
|
var s = document.getElementById('s' + i);
|
|
s.classList.toggle('active', i === n);
|
|
s.classList.toggle('done', i < n);
|
|
}
|
|
}
|
|
function form2obj() {
|
|
var o = {}, els = document.querySelectorAll('#p2 input');
|
|
els.forEach(function (e) { o[e.name] = e.value; });
|
|
return o;
|
|
}
|
|
function post(action, data) {
|
|
return fetch('index.php?action=' + action, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: Object.keys(data).map(function (k) { return k + '=' + encodeURIComponent(data[k]); }).join('&')
|
|
}).then(function (r) { return r.json(); });
|
|
}
|
|
|
|
// 步骤1:环境检测
|
|
fetch('index.php?action=env').then(function (r) { return r.json(); }).then(function (res) {
|
|
var box = document.getElementById('envList');
|
|
if (!res.ok) { box.innerHTML = '<div class="hint">检测失败</div>'; return; }
|
|
var allOk = true, html = '';
|
|
res.items.forEach(function (it) {
|
|
if (!it.ok) allOk = false;
|
|
html += '<div class="env-item"><span>' + it.name + ' <span class="hint">(' + it.require + ')</span></span>'
|
|
+ '<span class="st ' + (it.ok ? 'ok' : 'bad') + '">' + it.current + (it.ok ? ' ✓' : ' ✗') + '</span></div>';
|
|
});
|
|
box.innerHTML = html;
|
|
document.getElementById('toStep2').disabled = !allOk;
|
|
if (!allOk) {
|
|
var d = document.createElement('div');
|
|
d.className = 'msg err'; d.style.display = 'block';
|
|
d.textContent = '存在不满足的环境要求,请先修复后刷新页面。';
|
|
box.appendChild(d);
|
|
}
|
|
});
|
|
document.getElementById('toStep2').onclick = function () { setStep(2); };
|
|
|
|
// 步骤2:测试连接
|
|
document.getElementById('testDb').onclick = function () {
|
|
var m = document.getElementById('dbMsg');
|
|
m.className = 'msg info'; m.textContent = '正在测试连接…';
|
|
post('dbtest', form2obj()).then(function (r) {
|
|
if (r.ok) { m.className = 'msg succ'; m.textContent = '连接成功,数据库已就绪。'; }
|
|
else { m.className = 'msg err'; m.textContent = '连接失败:' + (r.msg || '未知错误'); }
|
|
}).catch(function () { m.className = 'msg err'; m.textContent = '请求异常'; });
|
|
};
|
|
|
|
// 步骤2 -> 3:开始安装
|
|
document.getElementById('toStep3').onclick = function () {
|
|
var data = form2obj();
|
|
if (!data.db_name || !data.db_user) {
|
|
var m = document.getElementById('dbMsg');
|
|
m.className = 'msg err'; m.textContent = '请填写数据库名与用户名。';
|
|
return;
|
|
}
|
|
if (!data.admin_account || !data.admin_password) {
|
|
var m2 = document.getElementById('dbMsg');
|
|
m2.className = 'msg err'; m2.textContent = '请填写管理员账号与密码。';
|
|
return;
|
|
}
|
|
setStep(3);
|
|
post('install', data).then(function (r) {
|
|
var im = document.getElementById('installMsg');
|
|
if (r.ok) {
|
|
im.className = 'msg succ'; im.textContent = '数据库初始化完成,配置已写入。';
|
|
setStep(4);
|
|
} else {
|
|
im.className = 'msg err'; im.textContent = (r.msg || '安装失败');
|
|
}
|
|
}).catch(function () {
|
|
document.getElementById('installMsg').className = 'msg err';
|
|
document.getElementById('installMsg').textContent = '请求异常,请检查服务器日志。';
|
|
});
|
|
};
|
|
</script>
|
|
</body>
|
|
</html>
|