[优化] 界面优化

This commit is contained in:
ryan
2026-03-13 00:10:55 +08:00
parent b05bd608f2
commit 2ad6e9a2d0
@@ -111,6 +111,13 @@ function isCacheLevelsValue(value: string) {
return /^\d{1,2}(?::\d{1,2}){0,2}$/.test(value.trim()); return /^\d{1,2}(?::\d{1,2}){0,2}$/.test(value.trim());
} }
function extractMainConfigLines(content: string, matcher: RegExp) {
return content
.split('\n')
.map((line) => line.trim())
.filter((line) => line && matcher.test(line));
}
export function PerformancePage() { export function PerformancePage() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { user } = useAuth(); const { user } = useAuth();
@@ -357,16 +364,6 @@ export function PerformancePage() {
const handleCacheSave = () => { const handleCacheSave = () => {
void runBusyAction('performance-cache', async () => { void runBusyAction('performance-cache', async () => {
if (!isPositiveInteger(performanceFields.OpenRestyGzipMinLength)) {
throw new Error('gzip_min_length 必须为大于 0 的整数。');
}
const gzipLevel = Number.parseInt(
performanceFields.OpenRestyGzipCompLevel,
10,
);
if (Number.isNaN(gzipLevel) || gzipLevel < 1 || gzipLevel > 9) {
throw new Error('gzip_comp_level 必须在 1 到 9 之间。');
}
if (performanceFields.OpenRestyCacheEnabled) { if (performanceFields.OpenRestyCacheEnabled) {
if (!performanceFields.OpenRestyCachePath.trim()) { if (!performanceFields.OpenRestyCachePath.trim()) {
throw new Error('启用缓存时必须填写 proxy_cache_path 目录。'); throw new Error('启用缓存时必须填写 proxy_cache_path 目录。');
@@ -388,18 +385,6 @@ export function PerformancePage() {
await saveOptionEntries( await saveOptionEntries(
[ [
[
'OpenRestyGzipEnabled',
String(performanceFields.OpenRestyGzipEnabled),
],
[
'OpenRestyGzipMinLength',
performanceFields.OpenRestyGzipMinLength.trim(),
],
[
'OpenRestyGzipCompLevel',
performanceFields.OpenRestyGzipCompLevel.trim(),
],
['OpenRestyCachePath', performanceFields.OpenRestyCachePath.trim()], ['OpenRestyCachePath', performanceFields.OpenRestyCachePath.trim()],
[ [
'OpenRestyCacheLevels', 'OpenRestyCacheLevels',
@@ -439,6 +424,39 @@ export function PerformancePage() {
}); });
}; };
const handleGzipSave = () => {
void runBusyAction('performance-gzip', async () => {
if (!isPositiveInteger(performanceFields.OpenRestyGzipMinLength)) {
throw new Error('gzip_min_length 必须为大于 0 的整数。');
}
const gzipLevel = Number.parseInt(
performanceFields.OpenRestyGzipCompLevel,
10,
);
if (Number.isNaN(gzipLevel) || gzipLevel < 1 || gzipLevel > 9) {
throw new Error('gzip_comp_level 必须在 1 到 9 之间。');
}
await saveOptionEntries(
[
[
'OpenRestyGzipEnabled',
String(performanceFields.OpenRestyGzipEnabled),
],
[
'OpenRestyGzipMinLength',
performanceFields.OpenRestyGzipMinLength.trim(),
],
[
'OpenRestyGzipCompLevel',
performanceFields.OpenRestyGzipCompLevel.trim(),
],
],
'OpenResty 压缩参数已保存。',
);
});
};
const handleTemplateSave = () => { const handleTemplateSave = () => {
void runBusyAction('performance-template', async () => { void runBusyAction('performance-template', async () => {
await saveOptionEntries( await saveOptionEntries(
@@ -495,6 +513,15 @@ export function PerformancePage() {
); );
} }
const cachePreviewLines = extractMainConfigLines(
preview.main_config,
/proxy_cache_path|proxy_cache_key|proxy_cache_lock(?:_timeout)?|proxy_cache_use_stale/,
);
const gzipPreviewLines = extractMainConfigLines(
preview.main_config,
/gzip(?:_| )/,
);
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<PageHeader <PageHeader
@@ -812,18 +839,19 @@ export function PerformancePage() {
</div> </div>
</AppCard> </AppCard>
<div className="space-y-6">
<AppCard <AppCard
title="OpenResty 压缩与缓存" title="OpenResty 压缩"
description="缓存能力仍限定在单节点反代优化场景,不扩展为独立缓存产品。" description="单独维护 gzip 相关参数,避免与缓存配置混在一起。"
action={ action={
<PrimaryButton <PrimaryButton
type="button" type="button"
onClick={handleCacheSave} onClick={handleGzipSave}
disabled={busyKey === 'performance-cache'} disabled={busyKey === 'performance-gzip'}
> >
{busyKey === 'performance-cache' {busyKey === 'performance-gzip'
? '保存中...' ? '保存中...'
: '保存压缩与缓存'} : '保存压缩设置'}
</PrimaryButton> </PrimaryButton>
} }
> >
@@ -840,17 +868,20 @@ export function PerformancePage() {
})) }))
} }
/> />
<ToggleField <div className="rounded-2xl border border-[var(--border-default)] bg-[var(--surface-elevated)] px-4 py-4">
label="proxy cache" <p className="text-xs tracking-[0.2em] text-[var(--foreground-muted)] uppercase">
description="是否启用单节点代理缓存。" 当前压缩预览
checked={performanceFields.OpenRestyCacheEnabled} </p>
onChange={(checked) => {gzipPreviewLines.length > 0 ? (
setPerformanceFields((previous) => ({ <CodeBlock className="mt-3 text-xs leading-6 whitespace-pre-wrap">
...previous, {gzipPreviewLines.join('\n')}
OpenRestyCacheEnabled: checked, </CodeBlock>
})) ) : (
} <p className="mt-3 text-sm leading-6 text-[var(--foreground-secondary)]">
/> 当前主配置预览中没有压缩指令。
</p>
)}
</div>
<ResourceField label="gzip_min_length"> <ResourceField label="gzip_min_length">
<ResourceInput <ResourceInput
type="number" type="number"
@@ -878,10 +909,124 @@ export function PerformancePage() {
/> />
</ResourceField> </ResourceField>
</div> </div>
<div className="grid gap-5 md:grid-cols-2"> </div>
<ResourceField label="proxy_cache_path"> </AppCard>
<AppCard
title="OpenResty 缓存"
description="缓存能力仍限定在单节点反代优化场景,不扩展为独立缓存产品。"
action={
<div className="flex flex-wrap gap-2">
<SecondaryButton
type="button"
onClick={() =>
setPerformanceFields((previous) => ({
...previous,
OpenRestyCacheEnabled:
!previous.OpenRestyCacheEnabled,
}))
}
>
{performanceFields.OpenRestyCacheEnabled
? '先关闭缓存'
: '先启用缓存'}
</SecondaryButton>
<PrimaryButton
type="button"
onClick={handleCacheSave}
disabled={busyKey === 'performance-cache'}
>
{busyKey === 'performance-cache'
? '保存中...'
: performanceFields.OpenRestyCacheEnabled
? '保存缓存设置'
: '保存为关闭状态'}
</PrimaryButton>
</div>
}
>
<div className="space-y-5">
<div className="grid gap-4 md:grid-cols-2">
<div className="rounded-2xl border border-[var(--border-default)] bg-[var(--surface-elevated)] px-4 py-4">
<p className="text-xs tracking-[0.2em] text-[var(--foreground-muted)] uppercase">
缓存状态
</p>
<div className="mt-3 flex flex-wrap items-center gap-3">
<StatusBadge
label={
performanceFields.OpenRestyCacheEnabled
? '已启用,主配置会渲染缓存指令'
: '已关闭,主配置不会渲染缓存指令'
}
variant={
performanceFields.OpenRestyCacheEnabled
? 'success'
: 'warning'
}
/>
<button
type="button"
onClick={() =>
setPerformanceFields((previous) => ({
...previous,
OpenRestyCacheEnabled:
!previous.OpenRestyCacheEnabled,
}))
}
className={[
'inline-flex items-center rounded-full px-3 py-1.5 text-xs font-medium transition',
performanceFields.OpenRestyCacheEnabled
? 'bg-[var(--status-danger-soft)] text-[var(--status-danger-foreground)]'
: 'bg-[var(--brand-primary-soft)] text-[var(--brand-primary)]',
].join(' ')}
>
{performanceFields.OpenRestyCacheEnabled
? '点击关闭'
: '点击启用'}
</button>
</div>
<p className="mt-3 text-xs leading-5 text-[var(--foreground-secondary)]">
`max_size` 会跟随 `proxy_cache_path`
一起渲染,不会单独占一行。
</p>
</div>
<div className="rounded-2xl border border-[var(--border-default)] bg-[var(--surface-elevated)] px-4 py-4">
<p className="text-xs tracking-[0.2em] text-[var(--foreground-muted)] uppercase">
当前缓存预览
</p>
{cachePreviewLines.length > 0 ? (
<CodeBlock className="mt-3 text-xs leading-6 whitespace-pre-wrap">
{cachePreviewLines.join('\n')}
</CodeBlock>
) : (
<p className="mt-3 text-sm leading-6 text-[var(--foreground-secondary)]">
当前主配置预览中没有缓存指令。启用缓存并保存后,会出现
`proxy_cache_path ... max_size=...;` 这一行。
</p>
)}
</div>
</div>
<div
className={[
'grid gap-5 transition md:grid-cols-2',
performanceFields.OpenRestyCacheEnabled
? 'opacity-100'
: 'opacity-60',
].join(' ')}
>
<ResourceField
label="proxy_cache_path"
hint={
performanceFields.OpenRestyCacheEnabled
? '缓存目录,启用缓存时必填。'
: '缓存关闭时暂不生效。'
}
>
<ResourceInput <ResourceInput
value={performanceFields.OpenRestyCachePath} value={performanceFields.OpenRestyCachePath}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(event) => onChange={(event) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -894,6 +1039,7 @@ export function PerformancePage() {
<ResourceField label="levels"> <ResourceField label="levels">
<ResourceInput <ResourceInput
value={performanceFields.OpenRestyCacheLevels} value={performanceFields.OpenRestyCacheLevels}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(event) => onChange={(event) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -906,6 +1052,7 @@ export function PerformancePage() {
<ResourceField label="inactive"> <ResourceField label="inactive">
<ResourceInput <ResourceInput
value={performanceFields.OpenRestyCacheInactive} value={performanceFields.OpenRestyCacheInactive}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(event) => onChange={(event) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -918,6 +1065,7 @@ export function PerformancePage() {
<ResourceField label="max_size"> <ResourceField label="max_size">
<ResourceInput <ResourceInput
value={performanceFields.OpenRestyCacheMaxSize} value={performanceFields.OpenRestyCacheMaxSize}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(event) => onChange={(event) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -930,6 +1078,7 @@ export function PerformancePage() {
<ResourceField label="cache key template"> <ResourceField label="cache key template">
<ResourceInput <ResourceInput
value={performanceFields.OpenRestyCacheKeyTemplate} value={performanceFields.OpenRestyCacheKeyTemplate}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(event) => onChange={(event) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -942,6 +1091,7 @@ export function PerformancePage() {
label="proxy_cache_lock" label="proxy_cache_lock"
description="是否启用 proxy_cache_lock。" description="是否启用 proxy_cache_lock。"
checked={performanceFields.OpenRestyCacheLockEnabled} checked={performanceFields.OpenRestyCacheLockEnabled}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(checked) => onChange={(checked) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -952,6 +1102,7 @@ export function PerformancePage() {
<ResourceField label="proxy_cache_lock_timeout"> <ResourceField label="proxy_cache_lock_timeout">
<ResourceInput <ResourceInput
value={performanceFields.OpenRestyCacheLockTimeout} value={performanceFields.OpenRestyCacheLockTimeout}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(event) => onChange={(event) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -964,6 +1115,7 @@ export function PerformancePage() {
<ResourceField label="proxy_cache_use_stale"> <ResourceField label="proxy_cache_use_stale">
<ResourceInput <ResourceInput
value={performanceFields.OpenRestyCacheUseStale} value={performanceFields.OpenRestyCacheUseStale}
disabled={!performanceFields.OpenRestyCacheEnabled}
onChange={(event) => onChange={(event) =>
setPerformanceFields((previous) => ({ setPerformanceFields((previous) => ({
...previous, ...previous,
@@ -977,6 +1129,7 @@ export function PerformancePage() {
</AppCard> </AppCard>
</div> </div>
</div> </div>
</div>
) : ( ) : (
<div className="space-y-6"> <div className="space-y-6">
<AppCard <AppCard