96 lines
3.4 KiB
TypeScript
96 lines
3.4 KiB
TypeScript
import { useCallback, useEffect, useState, type FormEvent } from 'react';
|
||
import { getMindSpaceAdminConfig, updateMindSpaceAdminConfig } from '../../api/client';
|
||
import type { MindSpaceAdminConfig } from '../../types';
|
||
|
||
function safeConfig(config: MindSpaceAdminConfig | null): MindSpaceAdminConfig {
|
||
return config ?? { publicPageLimit: 10, analytics: { enabled: false, websiteId: '', analyticsUrl: 'http://127.0.0.1:3100', domains: '127.0.0.1,localhost', idSecretConfigured: false } };
|
||
}
|
||
|
||
export function MindSpacePage() {
|
||
const [config, setConfig] = useState<MindSpaceAdminConfig | null>(null);
|
||
const [limit, setLimit] = useState('10');
|
||
const [loading, setLoading] = useState(true);
|
||
const [busy, setBusy] = useState(false);
|
||
const [error, setError] = useState<string | null>(null);
|
||
const [message, setMessage] = useState<string | null>(null);
|
||
|
||
const load = useCallback(async () => {
|
||
setLoading(true);
|
||
setError(null);
|
||
setMessage(null);
|
||
try {
|
||
const nextConfig = await getMindSpaceAdminConfig();
|
||
setConfig(nextConfig);
|
||
setLimit(String(nextConfig.publicPageLimit));
|
||
} catch (err) {
|
||
setError(err instanceof Error ? err.message : '加载 MindSpace 配置失败');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
void load();
|
||
}, [load]);
|
||
|
||
const handleSave = async (event: FormEvent) => {
|
||
event.preventDefault();
|
||
setBusy(true);
|
||
setError(null);
|
||
setMessage(null);
|
||
try {
|
||
const nextConfig = await updateMindSpaceAdminConfig({ publicPageLimit: Number(limit) });
|
||
setConfig(nextConfig);
|
||
setLimit(String(nextConfig.publicPageLimit));
|
||
setMessage(`已更新为 ${nextConfig.publicPageLimit},主站会立即按新值校验。`);
|
||
} catch (err) {
|
||
setError(err instanceof Error ? err.message : '保存 MindSpace 配置失败');
|
||
} finally {
|
||
setBusy(false);
|
||
}
|
||
};
|
||
|
||
const current = safeConfig(config);
|
||
|
||
return (
|
||
<div className="admin-page">
|
||
<div className="admin-page-head">
|
||
<h2>MindSpace 配置</h2>
|
||
<p className="muted">公开页面数量上限由这里统一管理,主站会直接读取数据库配置。</p>
|
||
</div>
|
||
|
||
{error && <p className="banner banner-error">{error}</p>}
|
||
{message && <p className="banner banner-info">{message}</p>}
|
||
|
||
<section className="admin-card">
|
||
<h2>公开页面上限</h2>
|
||
<p className="muted">
|
||
当前值:{loading ? '—' : current.publicPageLimit}。建议在修改后同步检查主站发布流程。
|
||
</p>
|
||
<form className="admin-form" onSubmit={handleSave}>
|
||
<label className="admin-form-row">
|
||
<span>每个用户最多可在线的公开页面数</span>
|
||
<input
|
||
type="number"
|
||
min={1}
|
||
step={1}
|
||
value={limit}
|
||
onChange={(e) => setLimit(e.target.value)}
|
||
inputMode="numeric"
|
||
required
|
||
/>
|
||
</label>
|
||
<div className="admin-actions">
|
||
<button type="submit" className="send-btn" disabled={busy || loading}>
|
||
{busy ? '保存中...' : '保存配置'}
|
||
</button>
|
||
<button type="button" className="ghost-btn" onClick={() => void load()} disabled={busy}>
|
||
重新加载
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</section>
|
||
</div>
|
||
);
|
||
}
|