轻提示铺开到全部页面;内核状态悬停变重启;GEO 支持单文件下载
侧栏动作排撤掉重启图标,内核状态(圆点加版本号)本身变成按钮:悬停 换层显示「重启内核」,不在线时只当状态看。行高压成 1 修掉圆点和等宽 字体不居中的问题。 四个页面的一次性反馈(保存、删除、更新订阅、断开连接、测延迟结论) 全部改走 toast,commit() 改返回成败给「失败不关对话框」用;持续状态 (连接页轮询失败、请求页日志流失败)留在页内,会自动消失的提示装不下 需要一直可见的信息。toast 加 info 类别给中性结论用。 GEO 每行的更新改成单独下载那一个文件:内核只有全量更新的口子,单文件 只能服务端自己下(POST /api/geo/sync),代价是只有形状校验(MaxMind 末尾标记、geodata 首字节,shared/geo.ts 带测试)且内核重启后才换用新 文件;「更新全部」文字按钮保留内核的全量口子,有完整校验和热加载。 上传两行的按钮改「选择或拖放文件」,投放区拖入高亮,恢复策略挪到 恢复行下方。
This commit is contained in:
@@ -123,9 +123,12 @@ function geoMeta(g: GeoFileStatus): string {
|
||||
return `${formatBytes(g.size)} · ${formatAgo(new Date(g.updatedAt), new Date())}`
|
||||
}
|
||||
|
||||
/** GEO 更新是运行时动作,不写配置文件。内核只有全量更新的口子,四行共用一个忙态。 */
|
||||
/**
|
||||
* 更新全部:让内核自己更新(运行时动作,带内核的完整校验和热加载,
|
||||
* 但只更新配置实际用到的类型)。
|
||||
*/
|
||||
async function updateGeo() {
|
||||
if (geoBusy.value || !kernel.value.online) return
|
||||
if (geoBusy.value || geoSyncing.value !== null || !kernel.value.online) return
|
||||
geoBusy.value = true
|
||||
try {
|
||||
await api.updateGeo()
|
||||
@@ -138,6 +141,24 @@ async function updateGeo() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 正在单独下载的那一行(configKey) */
|
||||
const geoSyncing = ref<string | null>(null)
|
||||
|
||||
/** 单独更新一个文件:服务端自己下载,内核重启后换用新文件。 */
|
||||
async function syncOne(g: GeoFileStatus) {
|
||||
if (geoBusy.value || geoSyncing.value !== null) return
|
||||
geoSyncing.value = g.configKey
|
||||
try {
|
||||
await api.syncGeoFile(g.configKey)
|
||||
toast(`${g.key} 已下载`, { hint: '内核还在用旧数据,重启内核后换用新文件。' })
|
||||
await loadGeo()
|
||||
} catch (error) {
|
||||
toastError(error)
|
||||
} finally {
|
||||
geoSyncing.value = null
|
||||
}
|
||||
}
|
||||
|
||||
/** 正在编辑下载地址的那一行(configKey),一次只开一行 */
|
||||
const geoEditing = ref<string | null>(null)
|
||||
const geoDraft = ref('')
|
||||
@@ -433,7 +454,18 @@ const backend = location.origin
|
||||
</section>
|
||||
|
||||
<section class="group">
|
||||
<h2 class="title">资源</h2>
|
||||
<div class="g-head">
|
||||
<h2 class="title">资源</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="tbtn"
|
||||
:title="kernel.online ? '让内核更新它用到的全部 GEO 文件' : '内核未连接'"
|
||||
:disabled="geoBusy || geoSyncing !== null || !kernel.online"
|
||||
@click="updateGeo"
|
||||
>
|
||||
<IconSync :class="geoBusy && 'spin'" /> 更新全部
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="geoFiles === null" class="faint">载入中</p>
|
||||
<p v-else-if="geoFiles.length === 0" class="faint">读不到 GEO 文件的状态。</p>
|
||||
<template v-else>
|
||||
@@ -455,11 +487,11 @@ const backend = location.origin
|
||||
<button
|
||||
type="button"
|
||||
class="ico"
|
||||
:title="kernel.online ? '更新(有变化的 GEO 文件会一并更新)' : '内核未连接'"
|
||||
:disabled="geoBusy || !kernel.online"
|
||||
@click="updateGeo"
|
||||
title="单独下载这一个文件(重启内核后生效)"
|
||||
:disabled="geoBusy || geoSyncing !== null"
|
||||
@click="syncOne(g)"
|
||||
>
|
||||
<IconSync :class="geoBusy && 'spin'" />
|
||||
<IconSync :class="geoSyncing === g.configKey && 'spin'" />
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
@@ -673,6 +705,42 @@ const backend = location.origin
|
||||
}
|
||||
|
||||
/* ── 资源 ────────────────────────────────────── */
|
||||
.g-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.g-head .title {
|
||||
margin-bottom: var(--s-3);
|
||||
}
|
||||
|
||||
/* 文字按钮:图标加一个词,不占按钮的份量 */
|
||||
.tbtn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--s-2);
|
||||
padding: var(--s-1) var(--s-2);
|
||||
border: none;
|
||||
border-radius: var(--r-sm);
|
||||
background: none;
|
||||
color: var(--c-text-soft);
|
||||
font-size: var(--t-sm);
|
||||
cursor: pointer;
|
||||
}
|
||||
.tbtn:hover:not(:disabled) {
|
||||
background: var(--c-surface-sunken);
|
||||
color: var(--c-text);
|
||||
}
|
||||
.tbtn:disabled {
|
||||
color: var(--c-text-faint);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.tbtn svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.g-right {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user