支持高程数据集删除

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-05-03 11:13:25 +08:00
parent 9bd3802603
commit 244834c549
4 changed files with 125 additions and 2 deletions
+13
View File
@@ -21,6 +21,7 @@ from ...services.elevation_service import (
analyze_dataset,
create_apply_job,
create_dataset,
delete_dataset,
get_job_by_id,
list_datasets,
list_jobs,
@@ -71,6 +72,18 @@ def update_elevation_dataset(
return updated
@router.delete("/datasets/{dataset_id}")
def delete_elevation_dataset(
dataset_id: str,
_: CurrentUser = Depends(require_permission("elevation.manage")),
db: Session = Depends(get_db),
) -> dict[str, bool]:
deleted = delete_dataset(db, dataset_id)
if not deleted:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="高程数据集不存在")
return {"success": True}
@router.post("/datasets/{dataset_id}/analyze", response_model=ElevationDatasetAnalyzeResponse)
def analyze_elevation_dataset(
dataset_id: str,
+36 -1
View File
@@ -9,7 +9,7 @@ from tempfile import NamedTemporaryFile
from typing import Any
from fastapi import HTTPException, status
from sqlalchemy import func, select
from sqlalchemy import delete, func, select
from sqlalchemy.orm import Session
from ..core.database import SessionLocal
@@ -261,6 +261,41 @@ def update_dataset(
return serialize_dataset(saved)
def delete_dataset(
db: Session,
dataset_id: str,
) -> bool:
item = get_dataset_by_id(db, dataset_id)
if not item:
return False
running_job_count = int(
db.scalar(
select(func.count())
.select_from(ElevationApplyJob)
.where(
ElevationApplyJob.dataset_id == dataset_id,
ElevationApplyJob.status == "running",
)
)
or 0
)
if running_job_count > 0:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"该数据集存在 {running_job_count} 个运行中的回填任务,暂不能删除",
)
db.execute(delete(ElevationApplyJob).where(ElevationApplyJob.dataset_id == dataset_id))
db.delete(item)
db.commit()
_publish_elevation_change(
"elevation.dataset.deleted",
{"action": "dataset_deleted", "dataset_id": dataset_id},
)
return True
def analyze_dataset(
db: Session,
*,
+28
View File
@@ -89,3 +89,31 @@
- 提交:`556da5c`
- 信息:`改造高程预览为地形网格渲染`
- 已推送到 `origin/dev`
## Work Log - 高程数据集支持删除(2026-05-03)
- 背景:
- Issue `FL-180` 需要“高程数据集支持删除”。
- 现有高程管理仅支持创建/更新/分析/预览,缺少删除闭环。
- 本次改动:
- 后端新增数据集删除能力:
- 文件:`api/app/services/elevation_service.py`
- 新增 `delete_dataset(db, dataset_id)`
- 数据集不存在返回 `False`
- 存在运行中回填任务时返回 `409`,避免删除过程中任务写入异常;
- 删除前先清理关联 `elevation_apply_job` 记录,再删除数据集;
- 发布 `elevation.dataset.deleted` 主题事件,触发前端数据刷新。
- 后端新增删除接口:
- 文件:`api/app/api/v1/elevation.py`
- 新增 `DELETE /api/v1/elevation/datasets/{dataset_id}`(权限:`elevation.manage`)。
- 前端高程管理页新增删除入口:
- 文件:`web/src/app/admin/elevation/page.tsx`
- 数据集操作列新增“删除”;
- 使用 `App.useApp().modal.confirm` 二次确认;
- 删除成功后提示并刷新数据集/任务列表,同时清理预览弹窗状态。
- 风险与影响:
- 删除数据集会同时删除其关联的回填任务记录(仅记录,不会回滚已写入杆塔的高程值)。
- 若数据集存在运行中任务,接口会拒绝删除并提示先等待任务结束。
+48 -1
View File
@@ -4,6 +4,7 @@ import Link from "next/link";
import { useCallback, useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
App,
Alert,
Empty,
Form,
@@ -89,6 +90,7 @@ function formatDate(value: string | null): string {
}
export default function AdminElevationPage() {
const { modal } = App.useApp();
const queryClient = useQueryClient();
const { user, initializing, hasPermission, fetchWithAuth } = useAuth();
const [messageApi, messageContextHolder] = message.useMessage();
@@ -283,6 +285,33 @@ export default function AdminElevationPage() {
},
});
const datasetDeleteMutation = useMutation({
mutationFn: async (datasetId: string) => {
const response = await fetchWithAuth(`/api/v1/elevation/datasets/${datasetId}`, {
method: "DELETE",
});
if (!response.ok) {
throw new Error(await readApiError(response));
}
},
onSuccess: async () => {
setSuccess("高程数据集已删除");
setError("");
messageApi.success("高程数据集已删除");
setPreviewModalOpen(false);
setPreviewDataset(null);
setPreviewData(null);
setPreviewLoading(false);
await refreshElevationData();
},
onError: (candidate) => {
const nextError = candidate instanceof Error ? candidate.message : "删除高程数据集失败";
setError(nextError);
setSuccess("");
messageApi.error(nextError);
},
});
const datasets = datasetsQuery.data?.items ?? [];
const jobs = jobsQuery.data?.items ?? [];
const lines = linesQuery.data?.items ?? [];
@@ -383,11 +412,29 @@ export default function AdminElevationPage() {
>
{analyzingDatasetId === row.id ? "分析中..." : "分析"}
</Typography.Link>
<Typography.Link
disabled={!canManage || datasetDeleteMutation.isPending}
onClick={() => {
if (!canManage || datasetDeleteMutation.isPending) return;
modal.confirm({
title: "删除高程数据集",
content: `确认删除数据集「${row.code} - ${row.name}」?该操作会同时删除关联的回填任务记录,且不可恢复。`,
okText: "确认删除",
okButtonProps: { danger: true, loading: datasetDeleteMutation.isPending },
cancelText: "取消",
onOk: async () => {
await datasetDeleteMutation.mutateAsync(row.id);
},
});
}}
>
</Typography.Link>
</Space>
),
},
],
[analyzeMutation, analyzingDatasetId, canManage, fetchWithAuth, messageApi],
[analyzeMutation, analyzingDatasetId, canManage, datasetDeleteMutation, fetchWithAuth, messageApi, modal],
);
const jobColumns = useMemo<ColumnsType<ElevationApplyJobSummary>>(