refactor(admin): remove geoserver config UI

This commit is contained in:
2026-06-12 15:28:14 +08:00
parent f6d2e19397
commit 7cd0c61181
+4 -258
View File
@@ -91,18 +91,6 @@ type ProjectDatabaseConfig = {
has_dsn: boolean; has_dsn: boolean;
}; };
type ProjectGeoServerConfig = {
id?: string | null;
project_id: string;
gs_base_url?: string | null;
gs_admin_user?: string | null;
gs_datastore_name: string;
default_extent?: Record<string, unknown> | null;
srid: number;
configured?: boolean;
has_password: boolean;
};
type DatabaseHealth = { type DatabaseHealth = {
ok: boolean; ok: boolean;
detail: string; detail: string;
@@ -166,15 +154,6 @@ const createDefaultDatabaseForms = () => ({
iot_data: { ...defaultDatabaseForms.iot_data }, iot_data: { ...defaultDatabaseForms.iot_data },
}); });
const defaultGeoserverForm = {
gs_base_url: "",
gs_admin_user: "",
gs_admin_password: "",
gs_datastore_name: "ds_postgis",
default_extent: "",
srid: 4326,
};
const getBusinessRoleLabel = (role: string) => const getBusinessRoleLabel = (role: string) =>
businessRoleOptions.find((option) => option.value === role)?.label ?? role; businessRoleOptions.find((option) => option.value === role)?.label ?? role;
@@ -363,8 +342,6 @@ export const SystemAdminPanel = () => {
const [members, setMembers] = useState<ProjectMember[]>([]); const [members, setMembers] = useState<ProjectMember[]>([]);
const [projects, setProjects] = useState<AdminProject[]>([]); const [projects, setProjects] = useState<AdminProject[]>([]);
const [databases, setDatabases] = useState<ProjectDatabaseConfig[]>([]); const [databases, setDatabases] = useState<ProjectDatabaseConfig[]>([]);
const [geoserverConfig, setGeoserverConfig] =
useState<ProjectGeoServerConfig | null>(null);
const [currentAdmin, setCurrentAdmin] = useState<MetadataUser | null>(null); const [currentAdmin, setCurrentAdmin] = useState<MetadataUser | null>(null);
const [adminChecked, setAdminChecked] = useState(false); const [adminChecked, setAdminChecked] = useState(false);
const [isAuthorized, setIsAuthorized] = useState(false); const [isAuthorized, setIsAuthorized] = useState(false);
@@ -388,7 +365,6 @@ export const SystemAdminPanel = () => {
biz_data: null, biz_data: null,
iot_data: null, iot_data: null,
}); });
const [geoserverForm, setGeoserverForm] = useState(defaultGeoserverForm);
const activeUsers = useMemo( const activeUsers = useMemo(
() => users.filter((user) => user.is_active).length, () => users.filter((user) => user.is_active).length,
@@ -532,36 +508,6 @@ export const SystemAdminPanel = () => {
}); });
}, [projectId]); }, [projectId]);
const loadGeoserverConfig = useCallback(async () => {
if (!projectId.trim()) return;
const response = await apiFetch(
`${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/geoserver`,
);
if (response.status === 404) {
const errorText = await readErrorText(response);
if (isFastApiRouteNotFound(response, errorText)) {
setMetadataConfigAvailable(false);
}
setGeoserverConfig(null);
setGeoserverForm(defaultGeoserverForm);
return;
}
if (!response.ok) {
throw new Error(await readErrorText(response));
}
setMetadataConfigAvailable(true);
const payload = (await response.json()) as ProjectGeoServerConfig;
setGeoserverConfig(payload);
setGeoserverForm({
gs_base_url: payload.gs_base_url ?? "",
gs_admin_user: payload.gs_admin_user ?? "",
gs_admin_password: "",
gs_datastore_name: payload.gs_datastore_name || "ds_postgis",
default_extent: formatJsonField(payload.default_extent),
srid: payload.srid || 4326,
});
}, [projectId]);
useEffect(() => { useEffect(() => {
let cancelled = false; let cancelled = false;
@@ -657,18 +603,16 @@ export const SystemAdminPanel = () => {
if (!isAuthorized || !hasProjectId || !metadataConfigAvailable) return; if (!isAuthorized || !hasProjectId || !metadataConfigAvailable) return;
setDatabaseHealth({ biz_data: null, iot_data: null }); setDatabaseHealth({ biz_data: null, iot_data: null });
loadDatabases().catch((err) => setError(String(err))); loadDatabases().catch((err) => setError(String(err)));
loadGeoserverConfig().catch((err) => setError(String(err)));
}, [ }, [
hasProjectId, hasProjectId,
isAuthorized, isAuthorized,
loadDatabases, loadDatabases,
loadGeoserverConfig,
metadataConfigAvailable, metadataConfigAvailable,
]); ]);
useEffect(() => { useEffect(() => {
if (!metadataConfigAvailable && tab !== 4) { if (!metadataConfigAvailable && tab !== 3) {
setTab(4); setTab(3);
} }
}, [metadataConfigAvailable, tab]); }, [metadataConfigAvailable, tab]);
@@ -769,8 +713,6 @@ export const SystemAdminPanel = () => {
setMembers([]); setMembers([]);
setDatabases([]); setDatabases([]);
setDatabaseForms(createDefaultDatabaseForms()); setDatabaseForms(createDefaultDatabaseForms());
setGeoserverConfig(null);
setGeoserverForm(defaultGeoserverForm);
setDatabaseHealth({ biz_data: null, iot_data: null }); setDatabaseHealth({ biz_data: null, iot_data: null });
}; };
@@ -957,51 +899,6 @@ export const SystemAdminPanel = () => {
await loadDatabases(); await loadDatabases();
}; };
const saveGeoserverConfig = async (event: FormEvent) => {
event.preventDefault();
if (!projectId.trim()) return;
setError(null);
setMessage(null);
try {
const payload: Record<string, unknown> = {
gs_base_url: geoserverForm.gs_base_url.trim() || null,
gs_admin_user: geoserverForm.gs_admin_user.trim() || null,
gs_datastore_name: geoserverForm.gs_datastore_name.trim() || "ds_postgis",
default_extent: parseOptionalJsonObject(
geoserverForm.default_extent,
"默认范围",
),
srid: Number(geoserverForm.srid),
};
if (geoserverForm.gs_admin_password.trim()) {
payload.gs_admin_password = geoserverForm.gs_admin_password.trim();
}
const response = await apiFetch(
`${config.BACKEND_URL}/api/v1/admin/projects/${projectId.trim()}/geoserver`,
{
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
},
);
if (!response.ok) {
const errorText = await readErrorText(response);
if (isFastApiRouteNotFound(response, errorText)) {
setMetadataConfigAvailable(false);
return;
}
throw new Error(errorText);
}
const saved = (await response.json()) as ProjectGeoServerConfig;
setGeoserverConfig(saved);
setGeoserverForm((current) => ({ ...current, gs_admin_password: "" }));
setMessage("GeoServer 配置已保存");
await loadGeoserverConfig();
} catch (err) {
setError(String(err));
}
};
return ( return (
<Box <Box
sx={{ sx={{
@@ -1089,7 +986,7 @@ export const SystemAdminPanel = () => {
)} )}
{isAuthorized && !metadataConfigAvailable && ( {isAuthorized && !metadataConfigAvailable && (
<Alert severity="warning" sx={{ borderRadius: 2 }}> <Alert severity="warning" sx={{ borderRadius: 2 }}>
/api/v1/admin/projects 使 GeoServer /api/v1/admin/projects 使
</Alert> </Alert>
)} )}
@@ -1226,17 +1123,11 @@ export const SystemAdminPanel = () => {
label="数据库配置" label="数据库配置"
disabled={!metadataConfigAvailable} disabled={!metadataConfigAvailable}
/> />
<Tab
icon={<SecurityIcon />}
iconPosition="start"
label="GeoServer"
disabled={!metadataConfigAvailable}
/>
<Tab icon={<PeopleIcon />} iconPosition="start" label="系统用户" /> <Tab icon={<PeopleIcon />} iconPosition="start" label="系统用户" />
</Tabs> </Tabs>
<Box sx={{ p: { xs: 2, md: 2.5 } }}> <Box sx={{ p: { xs: 2, md: 2.5 } }}>
{tab === 4 && ( {tab === 3 && (
<Stack spacing={2}> <Stack spacing={2}>
<SectionHeader <SectionHeader
title="系统用户" title="系统用户"
@@ -1912,151 +1803,6 @@ export const SystemAdminPanel = () => {
</Stack> </Stack>
)} )}
{tab === 3 && (
<Stack spacing={2}>
<SectionHeader
title="项目 GeoServer 配置"
description="维护当前管理项目的 GeoServer 服务、管理员账号、datastore、默认范围和 SRID。"
action={
<Button
startIcon={<RefreshIcon />}
variant="outlined"
onClick={loadGeoserverConfig}
disabled={!hasProjectId}
>
</Button>
}
/>
{!hasProjectId && (
<Alert severity="warning" sx={{ borderRadius: 2 }}>
</Alert>
)}
{hasProjectId && (
<Paper
component="form"
variant="outlined"
sx={{ p: 2, borderRadius: 2 }}
onSubmit={saveGeoserverConfig}
>
<Stack spacing={2}>
<Stack
direction={{ xs: "column", md: "row" }}
spacing={1}
alignItems={{ xs: "stretch", md: "center" }}
justifyContent="space-between"
>
<Box>
<Typography variant="subtitle2" fontWeight={800}>
{selectedProject?.name ?? projectId}
</Typography>
<Typography variant="body2" color="text.secondary">
{selectedProject?.gs_workspace ?? "未设置工作区"}
</Typography>
</Box>
<Chip
color={geoserverConfig?.has_password ? "success" : "default"}
label={
geoserverConfig?.has_password ? "密码已配置" : "未配置密码"
}
sx={{ alignSelf: { xs: "flex-start", md: "center" } }}
/>
</Stack>
<Stack direction={{ xs: "column", md: "row" }} spacing={1.5}>
<TextField
size="small"
label="Base URL"
value={geoserverForm.gs_base_url}
onChange={(event) =>
setGeoserverForm({
...geoserverForm,
gs_base_url: event.target.value,
})
}
fullWidth
/>
<TextField
size="small"
label="管理员账号"
value={geoserverForm.gs_admin_user}
onChange={(event) =>
setGeoserverForm({
...geoserverForm,
gs_admin_user: event.target.value,
})
}
fullWidth
/>
<TextField
size="small"
type="password"
label="管理员密码"
value={geoserverForm.gs_admin_password}
onChange={(event) =>
setGeoserverForm({
...geoserverForm,
gs_admin_password: event.target.value,
})
}
fullWidth
/>
</Stack>
<Stack direction={{ xs: "column", md: "row" }} spacing={1.5}>
<TextField
size="small"
label="Datastore"
value={geoserverForm.gs_datastore_name}
onChange={(event) =>
setGeoserverForm({
...geoserverForm,
gs_datastore_name: event.target.value,
})
}
fullWidth
required
/>
<TextField
size="small"
type="number"
label="SRID"
value={geoserverForm.srid}
onChange={(event) =>
setGeoserverForm({
...geoserverForm,
srid: Number(event.target.value),
})
}
sx={{ width: { xs: "100%", md: 180 } }}
required
/>
</Stack>
<TextField
size="small"
label="默认范围 JSON"
value={geoserverForm.default_extent}
onChange={(event) =>
setGeoserverForm({
...geoserverForm,
default_extent: event.target.value,
})
}
fullWidth
multiline
minRows={4}
placeholder='{"bbox":[120.1,30.1,120.2,30.2]}'
/>
<Stack direction="row" justifyContent="flex-end">
<Button type="submit" variant="contained" startIcon={<SaveIcon />}>
GeoServer
</Button>
</Stack>
</Stack>
</Paper>
)}
</Stack>
)}
</Box> </Box>
</Paper> </Paper>
<Dialog <Dialog