Pārlūkot izejas kodu

feat(remote/history): 新增远程会话 DELETE 接口支持与同步删除

bob.yuxinyang 1 mēnesi atpakaļ
vecāks
revīzija
d50d24aa61

+ 1 - 0
CelestiaTrace/Services/Network/NetworkServiceProtocol.swift

@@ -6,6 +6,7 @@ protocol NetworkServiceProtocol {
         _ session: CelestiaSession,
         deletedEventClientIDs: [String]
     ) async throws -> RemoteSession
+    func deleteSession(sessionID: String) async throws
     func fetchStorageQuota() async throws -> StorageQuota
     func uploadAsset(
         sessionID: String,

+ 8 - 0
CelestiaTrace/Services/Network/RemoteNetworkService.swift

@@ -162,6 +162,14 @@ final class RemoteNetworkService: NetworkServiceProtocol {
         return try await client.request("sessions", method: .post, body: try encoder.encode(payload), authenticated: true)
     }
 
+    func deleteSession(sessionID: String) async throws {
+        try await client.requestVoid(
+            "sessions/\(sessionID)",
+            method: .delete,
+            authenticated: true
+        )
+    }
+
     func fetchStorageQuota() async throws -> StorageQuota {
         try await client.request("storage/quota", authenticated: true)
     }

+ 28 - 4
CelestiaTrace/Views/History/SessionListView.swift

@@ -16,6 +16,7 @@ struct SessionListView: View {
     @State private var sessionPendingDeletion: CelestiaSession?
     @State private var selectedSession: CelestiaSession?
     @State private var showSessionDetail = false
+    @State private var deletingSessionID: UUID?
 
     var body: some View {
         NavigationStack {
@@ -53,12 +54,19 @@ struct SessionListView: View {
                 presenting: sessionPendingDeletion
             ) { session in
                 Button("取消", role: .cancel) {}
-                Button("删除", role: .destructive) {
-                    deleteSession(session)
+                Button(session.cloudSessionId == nil ? "删除" : "同时删除", role: .destructive) {
                     sessionPendingDeletion = nil
+                    Task {
+                        await deleteSession(session)
+                    }
                 }
+                .disabled(deletingSessionID != nil)
             } message: { session in
-                Text("删除「\(session.title)」后,相关录音和图片也会被删除,且无法恢复。")
+                if session.cloudSessionId != nil {
+                    Text("删除「\(session.title)」后,本地录音、图片以及已经同步到云端的记录都会一并删除,且无法恢复。")
+                } else {
+                    Text("删除「\(session.title)」后,相关录音和图片也会被删除,且无法恢复。")
+                }
             }
         }
     }
@@ -107,13 +115,29 @@ struct SessionListView: View {
         .contentMargins(.bottom, 18, for: .scrollContent)
     }
 
-    private func deleteSession(_ session: CelestiaSession) {
+    @MainActor
+    private func deleteSession(_ session: CelestiaSession) async {
+        guard deletingSessionID == nil else { return }
+        deletingSessionID = session.id
+        defer { deletingSessionID = nil }
+
         let storedPaths =
             [session.localAudioPath].compactMap { $0 } +
             session.audioChunks.map(\.localFilePath) +
             session.events.compactMap(\.localFilePath)
         let fileURLs = Set(storedPaths.compactMap { AudioPathHelper.resolveURL(for: $0) })
 
+        if let cloudSessionID = session.cloudSessionId {
+            do {
+                try await RemoteNetworkService().deleteSession(sessionID: cloudSessionID)
+            } catch APIError.server(let code, _) where code == 404 {
+                // The remote record is already gone, so local cleanup can continue.
+            } catch {
+                deletionError = "云端记录删除失败,本地记录未删除:\(error.localizedDescription)"
+                return
+            }
+        }
+
         modelContext.delete(session)
 
         do {

+ 19 - 0
Docs/RemoteAPI.openapi.yaml

@@ -295,6 +295,25 @@ paths:
               schema:
                 $ref: "#/components/schemas/ConflictEnvelope"
 
+  /sessions/{sessionId}:
+    parameters:
+      - $ref: "#/components/parameters/SessionId"
+    delete:
+      tags: [Sessions]
+      operationId: deleteSession
+      description: Soft-deletes the session and its assets for the current user.
+      responses:
+        "200":
+          description: Session deleted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DeleteEnvelope"
+        "401":
+          $ref: "#/components/responses/Error"
+        "404":
+          $ref: "#/components/responses/Error"
+
   /sessions/{sessionId}/assets:
     parameters:
       - $ref: "#/components/parameters/SessionId"