feat: 数据集版本管理支持删除历史版本

DatasetVersionList 新增 next_version_number,API 与 Mock 补充删除版本接口与并发控制,DatasetVersionBar 增加删除操作并对初始版本与最后版本禁用,DatasetPreviewView 接入删除流程,回归脚本与设计走查同步。
This commit is contained in:
caoxiaozhu
2026-07-14 14:47:12 +08:00
parent acbd6d91b3
commit 2bceb686c6
8 changed files with 373 additions and 22 deletions

View File

@@ -27,7 +27,10 @@ import {
activateDatasetVersion,
appendDatasetVersion,
createInitialVersionState,
deleteDatasetVersion,
DatasetVersionMutationError,
getActiveDatasetVersion,
normalizeDatasetVersionState,
} from './datasetVersions'
import type { StoredDatasetVersion, StoredDatasetVersionState } from './datasetVersions'
@@ -83,7 +86,13 @@ function getVersionState(fileId: string): StoredDatasetVersionState {
if (persisted) {
try {
const state = JSON.parse(persisted) as StoredDatasetVersionState
if (state.versions?.length && state.active_version_id) return state
if (state.versions?.length && state.active_version_id) {
const normalizedState = normalizeDatasetVersionState(state)
if (state.next_version_number !== normalizedState.next_version_number) {
persistVersionState(fileId, normalizedState)
}
return normalizedState
}
} catch {
// 版本数据损坏时回退到初始版本
}
@@ -100,6 +109,14 @@ function versionMetadata(version: StoredDatasetVersion) {
return metadata
}
function versionListResponse(state: StoredDatasetVersionState) {
return {
versions: state.versions.map(versionMetadata).sort((a, b) => b.version - a.version),
active_version_id: state.active_version_id,
next_version_number: state.next_version_number,
}
}
/** 通过路径 + method 匹配 mock 响应 */
async function handleMock(config: AxiosRequestConfig) {
await delay(150) // 模拟网络延迟
@@ -185,10 +202,7 @@ async function handleMock(config: AxiosRequestConfig) {
if (m && method === 'get') {
const fileId = decodeURIComponent(m[1])
const state = getVersionState(fileId)
return ok({
versions: state.versions.map(versionMetadata).sort((a, b) => b.version - a.version),
active_version_id: state.active_version_id,
})
return ok(versionListResponse(state))
}
if (m && method === 'post') {
const fileId = decodeURIComponent(m[1])
@@ -249,6 +263,30 @@ async function handleMock(config: AxiosRequestConfig) {
? ok({ version: versionMetadata(version), content: version.content })
: fail('数据集版本不存在', 404)
}
if (m && method === 'delete') {
const fileId = decodeURIComponent(m[1])
const versionId = decodeURIComponent(m[2])
const currentState = getVersionState(fileId)
if (params.expected_current_version_id !== currentState.active_version_id) {
return fail('当前版本已被其他用户更新,请刷新后重试', 409)
}
let nextState: StoredDatasetVersionState
try {
nextState = deleteDatasetVersion(currentState, versionId)
} catch (error) {
if (error instanceof DatasetVersionMutationError) {
return fail(error.message, error.status)
}
return fail('删除版本失败', 500)
}
try {
persistVersionState(fileId, nextState)
} catch {
return fail('浏览器 Mock 存储空间不足', 413)
}
return ok(versionListResponse(nextState))
}
// ==================== 训练任务 ====================
if (url === '/fine-tune' && method === 'get') return ok(mockFineTuneList)