会员服务器:上传肥牛应用源码 v1.5.1(fnnas.huiyuan 完整 fpk 工程结构)

含 app/server/server.cjs 服务端、app/www 网页(admin/auth/项目云/库备份/settings)、
app/ui 图标、cmd 安装脚本、config、wizard、manifest、图标与对接文档。
按仓库规则排除构建产物 *.fpk 与 .mimosa 缓存。
This commit is contained in:
dqb-dev
2026-10-02 00:03:20 +08:00
parent d9be73be89
commit 65755bf520
30 changed files with 2718 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
// 会员服务器 · 管理登录门(四页共用)
// · 页面引入本文件后:无有效登录态时全屏遮罩要求输入管理密码,登录成功写入 localStorage 并刷新
// · 同时包装 window.fetch:对同源 /api/ 请求自动附加 X-Admin-Token 头(页面业务代码无需改动)
// · 管理密码未设置时提示先到安装向导/应用设置中设置
(function () {
var TOKEN_KEY = 'hy_admin_token';
function 取token() { try { return localStorage.getItem(TOKEN_KEY) || ''; } catch (e) { return ''; } }
function 存token(t) { try { localStorage.setItem(TOKEN_KEY, t); } catch (e) { } }
// 原生 fetch 引用(遮罩内登录请求用原生,避免递归)
var 原fetch = window.fetch.bind(window);
// 包装 fetch:同源 /api/ 请求自动带 X-Admin-Token
window.fetch = function (input, init) {
try {
var url = typeof input === 'string' ? input : (input && input.url) || '';
if (url.indexOf('/api/') === 0) {
init = init || {};
var h = {};
if (init.headers && typeof init.headers === 'object' && !(init.headers instanceof Headers)) h = init.headers;
h['X-Admin-Token'] = 取token();
init.headers = h;
}
} catch (e) { }
return 原fetch(input, init);
};
window.HY = {
token: 取token,
logout: function () { try { localStorage.removeItem(TOKEN_KEY); } catch (e) { } location.reload(); }
};
// ---- 登录遮罩 ----
var 样式 = document.createElement('style');
样式.textContent =
'#hy-login{position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;background:#f5f6f8}' +
'#hy-login .box{background:#fff;border:1px solid #e3e6eb;border-radius:12px;box-shadow:0 12px 40px rgba(0,0,0,.12);padding:32px 34px;width:340px;max-width:92vw}' +
'#hy-login h3{margin:0 0 6px;font-size:18px;font-family:"Microsoft YaHei UI","Microsoft YaHei",sans-serif}' +
'#hy-login .sub{color:#7c8590;font-size:12px;margin:0 0 16px;font-family:"Microsoft YaHei UI","Microsoft YaHei",sans-serif}' +
'#hy-login input{width:100%;padding:9px 11px;border:1px solid #cfd5dd;border-radius:7px;font-size:14px;box-sizing:border-box}' +
'#hy-login input:focus{outline:none;border-color:#2563eb}' +
'#hy-login button{width:100%;margin-top:12px;padding:9px;border:none;border-radius:7px;background:#2563eb;color:#fff;font-size:14px;cursor:pointer}' +
'#hy-login button:hover{background:#1d54d7}' +
'#hy-login .err{color:#c53030;font-size:12px;min-height:16px;margin-top:10px;font-family:"Microsoft YaHei UI","Microsoft YaHei",sans-serif}';
document.head.appendChild(样式);
function 显示登录(提示语) {
var 旧 = document.getElementById('hy-login');
if (旧) 旧.remove();
var ov = document.createElement('div');
ov.id = 'hy-login';
ov.innerHTML = '<div class="box"><h3>会员服务器</h3><p class="sub">请输入管理密码登录'
+ (提示语 ? '(' + 提示语 + ')' : '') + '</p>'
+ '<input type="password" id="hy-pwd" placeholder="管理密码" autocomplete="current-password">'
+ '<button id="hy-btn">登 录</button><div class="err" id="hy-err"></div></div>';
document.body.appendChild(ov);
var pwd = ov.querySelector('#hy-pwd'), btn = ov.querySelector('#hy-btn'), err = ov.querySelector('#hy-err');
function 登录() {
var v = pwd.value;
if (!v) { err.textContent = '请输入管理密码'; return; }
btn.disabled = true; btn.textContent = '登录中…'; err.textContent = '';
原fetch('/api/admin/login', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ 密码: v })
}).then(function (r) { return r.json(); }).then(function (j) {
if (j.ok) { 存token(j.token); location.reload(); return; }
err.textContent = j.msg || '登录失败';
btn.disabled = false; btn.textContent = '登 录'; pwd.value = ''; pwd.focus();
}).catch(function (e) {
err.textContent = '请求失败: ' + e;
btn.disabled = false; btn.textContent = '登 录';
});
}
btn.onclick = 登录;
pwd.addEventListener('keydown', function (e) { if (e.key === 'Enter') 登录(); });
setTimeout(function () { pwd.focus(); }, 50);
}
function 校验登录态() {
原fetch('/api/admin/check', { headers: { 'X-Admin-Token': 取token() } })
.then(function (r) { return r.json(); })
.then(function (j) {
if (j.ok) return; // 已登录,页面正常
显示登录(j.adminConfigured ? '' : '首次使用请先在安装向导/应用设置中设置管理密码');
})
.catch(function () { 显示登录('无法连接服务器'); });
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', 校验登录态);
else 校验登录态();
})();