设置页第二轮:行内编辑、GEO 资源展开、恢复与导入分家

单值设置从常驻输入框改成 InlineEdit(纯文本加铅笔,Enter 或失焦提交,
失焦无效直接放弃——失焦是「我走了」,不该把人拽回来)。测速地址加恢复
默认按钮;内核参数逐项提交,不再攒一个保存按钮。

资源一节按文件展开:四类 GEO 文件的大小和更新时间由服务端 stat 内核
工作目录得来(GET /api/geo;文件名和大小写不敏感匹配照 constant/
path.go:18-20,193-224),下载地址可改(geox-url,config.go:363-368,
默认值 578-583)。行内的更新按钮仍是全量更新——内核只有这一个口子,
没变化的文件靠内容哈希跳过。

上传拆成两个入口:恢复只认带 Patchbay 标记的文件,导入收任意配置;
新增恢复策略(兼容只搬接管段落 listeners/proxy-groups/rules/
proxy-providers/rule-providers,覆盖整份替换)。平时是按钮,拖着文件
进窗口时整行变成投放区。
This commit is contained in:
2026-08-12 01:40:49 +08:00
parent 8eb98e2e9a
commit 2580c03bfa
10 changed files with 790 additions and 229 deletions
+39
View File
@@ -0,0 +1,39 @@
/**
* GEO 数据库文件的本地状态:多大、多久没更新了。
*
* 内核不提供这个信息,但文件就躺在它的工作目录里,和 Patchbay 服务端
* 在同一台机器上,直接 stat 就是。
*/
import { readdir, stat } from 'node:fs/promises'
import { join } from 'node:path'
import { DEFAULT_GEOX_URLS, GEO_FILES } from '../shared/geo.ts'
import type { GeoFileStatus } from '../shared/geo.ts'
import type { Env } from './env.ts'
export async function geoStatus(
env: Env,
geoxUrl: Record<string, unknown>,
): Promise<GeoFileStatus[]> {
const entries = await readdir(env.mihomoHome).catch(() => [] as string[])
return Promise.all(
GEO_FILES.map(async ({ key, configKey, file }) => {
// 内核找 GeoIP.dat/GeoSite.dat 时大小写不敏感(constant/path.go:193-224),这里照做
const actual = entries.find((name) => name.toLowerCase() === file.toLowerCase())
let size: number | null = null
let updatedAt: string | null = null
if (actual) {
const info = await stat(join(env.mihomoHome, actual)).catch(() => null)
if (info) {
size = info.size
updatedAt = info.mtime.toISOString()
}
}
const configured = geoxUrl[configKey]
const url =
typeof configured === 'string' && configured !== ''
? configured
: (DEFAULT_GEOX_URLS[configKey] ?? '')
return { key, configKey, url, size, updatedAt }
}),
)
}