fix(IOS-INFO-043): change source list nav to MaterialReaderView + add COS download

- LibraryDetailPage source list: Route.materialDetail → Route.materialReader
- KnowledgeSource: add fileId field for COS download
- MaterialReaderView: add COS download fallback in .task
- MaterialReaderView: add resolvedPath for downloaded file

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-06-19 11:34:21 +08:00
parent f25538cf5a
commit 915d5e3fe2
4 changed files with 39 additions and 7 deletions

View File

@ -630,6 +630,7 @@ struct CreateFolderRequest: Codable {
struct KnowledgeSource: Codable, Identifiable { struct KnowledgeSource: Codable, Identifiable {
let id: String let id: String
let knowledgeBaseId: String? let knowledgeBaseId: String?
let fileId: String?
let title: String? let title: String?
let originalFilename: String? let originalFilename: String?
let type: String? let type: String?

View File

@ -262,13 +262,12 @@ struct LibraryDetailPage: View {
Text("暂无资料来源").font(.system(size: 14)).foregroundColor(Color.zxF03).padding(.top, 40) Text("暂无资料来源").font(.system(size: 14)).foregroundColor(Color.zxF03).padding(.top, 40)
} else { } else {
ForEach(sources) { src in ForEach(sources) { src in
NavigationLink(value: Route.materialDetail( NavigationLink(value: Route.materialReader(
knowledgeBaseId: knowledgeBaseId, materialId: src.id,
fileName: src.originalFilename ?? src.title ?? "未命名",
fileType: materialTypeFromMime(src.mimeType),
fileSize: 0,
filePath: "", filePath: "",
uploadDate: src.createdAt materialType: materialTypeFromMime(src.mimeType),
knowledgeBaseId: knowledgeBaseId,
title: src.originalFilename ?? src.title ?? "未命名"
)) { )) {
HStack(spacing: 12) { HStack(spacing: 12) {
Image(systemName: src.type == "file" ? "doc" : "link") Image(systemName: src.type == "file" ? "doc" : "link")

View File

@ -109,10 +109,19 @@ struct MaterialReaderView: View {
@Environment(\.scenePhase) private var scenePhase @Environment(\.scenePhase) private var scenePhase
@State private var isParsing = false @State private var isParsing = false
@State private var parseMessage = "" @State private var parseMessage = ""
@State private var downloadedFilePath: String?
private let title: String private let title: String
private let knowledgeBaseId: String? private let knowledgeBaseId: String?
/// Resolved file path: uses downloaded temp file if original is empty/missing
private var resolvedPath: String {
if !vm.filePath.isEmpty && FileManager.default.fileExists(atPath: vm.filePath) {
return vm.filePath
}
return downloadedFilePath ?? vm.filePath
}
// V2 session manager (primary) + V1 collector (fallback) // V2 session manager (primary) + V1 collector (fallback)
private let sessionManager = ReadingRuntimeSessionManager.shared private let sessionManager = ReadingRuntimeSessionManager.shared
private let collector = ReadingEventCollector.shared private let collector = ReadingEventCollector.shared
@ -239,7 +248,30 @@ struct MaterialReaderView: View {
.padding(.bottom, 100) .padding(.bottom, 100)
} }
} }
.task { await vm.load() } .task {
if vm.filePath.isEmpty || !FileManager.default.fileExists(atPath: vm.filePath) {
if let kbId = knowledgeBaseId {
print("[MaterialReader] No local file, downloading from COS: \(vm.materialId)")
do {
let source = try await KnowledgeSourceService.shared.detail(kbId: kbId, id: vm.materialId)
if let fileId = source.fileId {
let downloadUrl = try await FileUploadService.shared.getDownloadUrl(fileId: fileId)
let url = URL(string: downloadUrl)!
let (data, _) = try await URLSession.shared.data(from: url)
let ext = source.originalFilename?.split(separator: ".").last.map(String.init) ?? "md"
let localURL = FileManager.default.temporaryDirectory
.appendingPathComponent("source_\(vm.materialId).\(ext)")
try data.write(to: localURL)
downloadedFilePath = localURL.path
print("[MaterialReader] Downloaded to: \(localURL.path), size: \(data.count)")
}
} catch {
print("[MaterialReader] COS download failed: \(error.localizedDescription)")
}
}
}
await vm.load()
}
.sheet(isPresented: $showQuickLook) { .sheet(isPresented: $showQuickLook) {
QuickLookPreview(url: URL(fileURLWithPath: vm.filePath)) QuickLookPreview(url: URL(fileURLWithPath: vm.filePath))
} }