feat: 接入PostgreSQL/MariaDB + 首次安装向导 + 登录页独立 + 设置重构 + 文件夹识别兜底

- 数据库层 lib/Db.php:统一 PDO 支持 pgsql/mysql/sqlite,连接参数存 data/db.json
  (git-ignored),migrate 建 ny_settings/ny_roster 表(三方言兼容 upsert)
- 配置/名单读写:bootstrap ny_load_config/ny_save_config 与 Roster 均改为
  '数据库可用则走 DB、否则回退 data/config.json/roster.json' 的文件降级模式
- 首次安装向导 install.php:选择存储后端(文件/PostgreSQL/MariaDB),测试连接+
  建表+写入卷王连接信息与默认满分;支持 ?force=1 重新配置
- 登录门分离:新增 login.php 独立登录页(仅需密码,账号预填)+logout.php+
  会话(ny_session_start/ny_is_auth/ny_login/ny_logout);index/dashboard 未安装
  跳 install、未登录跳 login;api.php 加会话保护与 auth_check
- 设置重构:删除卷王系统地址/接口前缀/登录账号/登录密码(连接信息由安装向导
  配置);新增布局配置(默认/成绩明细与缺考名单同行)与各试卷独立满分列表(默认
  分数作用于全部);工具栏布局下拉移除
- 文件夹识别兜底:app.js/dashboard.php 双策略 — mode 含 folder 优先,缺省时用
  parent_id 引用反推(应对部分版本无 mode 字段);空文件夹自动隐藏

验证:php -l 全部通过、node --check app.js 通过;SQLite 等价实测 Db 层
(migrate/config upsert/Roster 读写/ny_load_config)与会话辅助函数全部PASS;
e2e(内置服务器)验证路由:未装→install、装完→login、index/dashboard 未登录
跳转、api 401 保护、?force=1 重配、logout 302 均正确。本机无真实 pgsql/mysql
服务器,DB 连接按部署环境实测。
This commit is contained in:
2026-09-09 07:15:56 +08:00
parent 64d0116c0e
commit 8686eb99c7
11 changed files with 830 additions and 195 deletions
+23
View File
@@ -13,12 +13,27 @@ function cfg(): array
return ny_load_config();
}
// 会话/安装保护:除 auth_check 外,未安装或未登录一律拒访
if (!ny_is_installed()) {
ny_json(['ok' => false, 'msg' => '系统尚未安装,请先完成安装向导'], 503);
exit;
}
if ($action !== 'auth_check' && !ny_is_auth()) {
ny_json(['ok' => false, 'msg' => '未登录或会话已过期,请重新登录'], 401);
exit;
}
try {
switch ($action) {
// 登录状态检查
case 'auth_check':
ny_ok(['auth' => ny_is_auth(), 'installed' => ny_is_installed()]);
// ---------------- 配置 ----------------
case 'config_get':
$c = cfg();
$c['has_password'] = $c['password'] !== '';
unset($c['password']);
ny_ok($c);
case 'config_save':
@@ -40,6 +55,14 @@ try {
$new[$k] = filter_var($in[$k], FILTER_VALIDATE_BOOL);
}
}
// 布局配置
if (array_key_exists('layout', $in)) {
$new['layout'] = ($in['layout'] === 'side') ? 'side' : 'default';
}
// 各试卷独立满分(覆盖整个 full_scores 映射)
if (array_key_exists('full_scores', $in) && is_array($in['full_scores'])) {
$new['full_scores'] = $in['full_scores'];
}
$pwdIn = $in['password'] ?? null;
if ($pwdIn === null || $pwdIn === '' || $pwdIn === '******') {
$new['password'] = $old['password'];