feat(IOS-INFO-043): add 详情 and 整理知识点 toolbar buttons to MaterialReaderView
- MaterialReaderView: add info.circle button → MaterialDetailView - MaterialReaderView: add brain button → trigger parse API + status polling - MaterialReaderView: add triggerParse() with 2s poll loop - KnowledgeSourceService: add parse() method (POST /sources/:id/parse) - ImportStatusResponse: add jobId, progress fields - ParseResponse: new model for parse trigger response Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
fbf359ffe9
commit
123efb1612
Binary file not shown.
@ -577,13 +577,21 @@ struct CreateImportRequest: Codable {
|
||||
|
||||
struct ImportStatusResponse: Codable {
|
||||
let id: String
|
||||
let jobId: String?
|
||||
let status: String?
|
||||
let fileName: String?
|
||||
let knowledgeBaseId: String?
|
||||
let errorMessage: String?
|
||||
let progress: Int?
|
||||
let itemCount: Int?
|
||||
}
|
||||
|
||||
struct ParseResponse: Codable {
|
||||
let id: String?
|
||||
let jobId: String?
|
||||
let status: String?
|
||||
}
|
||||
|
||||
// MARK: - Import Candidate
|
||||
|
||||
struct ImportCandidate: Codable, Identifiable {
|
||||
|
||||
@ -546,6 +546,10 @@ class KnowledgeSourceService {
|
||||
func delete(kbId: String, id: String) async throws -> GenericSuccessResponse {
|
||||
return try await client.request("/knowledge-bases/\(kbId)/sources/\(id)", method: "DELETE")
|
||||
}
|
||||
|
||||
func parse(kbId: String, sourceId: String) async throws -> ParseResponse {
|
||||
return try await client.request("/knowledge-bases/\(kbId)/sources/\(sourceId)/parse", method: "POST")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Quiz
|
||||
|
||||
@ -107,6 +107,8 @@ struct MaterialReaderView: View {
|
||||
@State private var apiRestorePosition: ReadingPosition?
|
||||
|
||||
@Environment(\.scenePhase) private var scenePhase
|
||||
@State private var isParsing = false
|
||||
@State private var parseMessage = ""
|
||||
|
||||
private let title: String
|
||||
private let knowledgeBaseId: String?
|
||||
@ -191,6 +193,19 @@ struct MaterialReaderView: View {
|
||||
}
|
||||
|
||||
if let kbId = knowledgeBaseId {
|
||||
NavigationLink(value: Route.materialDetail(
|
||||
knowledgeBaseId: kbId,
|
||||
fileName: title.isEmpty ? "资料" : title,
|
||||
fileType: vm.materialType,
|
||||
fileSize: 0,
|
||||
filePath: vm.filePath,
|
||||
uploadDate: nil
|
||||
)) {
|
||||
Image(systemName: "info.circle")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(Color.zxF05)
|
||||
}
|
||||
|
||||
NavigationLink(value: Route.learningSession(
|
||||
taskTitle: title.isEmpty ? "学习资料" : title,
|
||||
taskType: "study",
|
||||
@ -200,6 +215,14 @@ struct MaterialReaderView: View {
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(Color.zxF05)
|
||||
}
|
||||
|
||||
Button {
|
||||
Task { await triggerParse(kbId: kbId, sourceId: vm.materialId) }
|
||||
} label: {
|
||||
Image(systemName: "brain.head.profile")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(Color.zxF05)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -708,6 +731,37 @@ private func formatDuration(_ seconds: Int) -> String {
|
||||
return "\(seconds / 3600)h\(String(format: "%02d", (seconds % 3600) / 60))m"
|
||||
}
|
||||
|
||||
private func triggerParse(kbId: String, sourceId: String) async {
|
||||
guard !isParsing else { return }
|
||||
isParsing = true
|
||||
parseMessage = "正在整理知识点..."
|
||||
print("[MaterialReader] triggerParse START kbId=\(kbId) sourceId=\(sourceId)")
|
||||
do {
|
||||
let result = try await KnowledgeSourceService.shared.parse(kbId: kbId, sourceId: sourceId)
|
||||
print("[MaterialReader] parse queued: id=\(result.jobId ?? "?"), status=\(result.status ?? "?")")
|
||||
parseMessage = "知识点整理任务已提交"
|
||||
// Poll status
|
||||
for _ in 0..<60 {
|
||||
try await Task.sleep(nanoseconds: 2_000_000_000)
|
||||
let status = try await DocumentImportService.shared.getStatus(id: result.jobId ?? result.id ?? "")
|
||||
print("[MaterialReader] parse status: \(status.status ?? "?")")
|
||||
if status.status == "completed" {
|
||||
parseMessage = "知识点整理完成"
|
||||
break
|
||||
} else if status.status == "failed" {
|
||||
parseMessage = "整理失败: \(status.errorMessage ?? "未知错误")"
|
||||
break
|
||||
} else {
|
||||
parseMessage = "整理中... \(status.progress ?? 0)%"
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("[MaterialReader] triggerParse ERROR: \(error.localizedDescription)")
|
||||
parseMessage = "整理失败: \(error.localizedDescription)"
|
||||
}
|
||||
isParsing = false
|
||||
}
|
||||
|
||||
private func formatFileSize(_ bytes: UInt64) -> String {
|
||||
if bytes < 1024 { return "\(bytes) B" }
|
||||
if bytes < 1024 * 1024 { return String(format: "%.1f KB", Double(bytes) / 1024) }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user