diff --git a/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift b/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift index d8026a6..0e307b2 100644 --- a/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift +++ b/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift @@ -260,38 +260,47 @@ struct LibraryDetailPage: View { Text("暂无资料来源").font(.system(size: 14)).foregroundColor(Color.zxF03).padding(.top, 40) } else { ForEach(sources) { src in - HStack(spacing: 12) { - Image(systemName: src.type == "file" ? "doc" : "link") - .font(.system(size: 18)).foregroundColor(Color.zxPurple) - .frame(width: 36, height: 36) - VStack(alignment: .leading, spacing: 2) { - Text(src.title ?? src.originalFilename ?? "未命名") - .font(.system(size: 15, weight: .medium)).foregroundColor(Color.zxF0).lineLimit(1) - if let len = src.textLength, len > 0 { - Text("\(len) 字") - .font(.system(size: 13)).foregroundColor(Color.zxF04) + NavigationLink(value: Route.materialDetail( + knowledgeBaseId: knowledgeBaseId, + fileName: src.originalFilename ?? src.title ?? "未命名", + fileType: materialTypeFromMime(src.mimeType), + fileSize: 0, + filePath: "", + uploadDate: src.createdAt + )) { + HStack(spacing: 12) { + Image(systemName: src.type == "file" ? "doc" : "link") + .font(.system(size: 18)).foregroundColor(Color.zxPurple) + .frame(width: 36, height: 36) + VStack(alignment: .leading, spacing: 2) { + Text(src.originalFilename ?? src.title ?? "未命名") + .font(.system(size: 15, weight: .medium)).foregroundColor(Color.zxF0).lineLimit(1) + if let len = src.textLength, len > 0 { + Text("\(len) 字") + .font(.system(size: 13)).foregroundColor(Color.zxF04) + } + // Reading status badge + if let status = sourceReadingStatus[src.id], status != "not_started" { + Text(status == "read" ? "已读" : "阅读中") + .font(.system(size: 10, weight: .medium)) + .foregroundColor(status == "read" ? Color.green : Color.zxPurple) + .padding(.horizontal, 6).padding(.vertical, 2) + .background((status == "read" ? Color.green : Color.zxPurple).opacity(0.1)) + .clipShape(Capsule()) + } } - // Reading status badge - if let status = sourceReadingStatus[src.id], status != "not_started" { - Text(status == "read" ? "已读" : "阅读中") - .font(.system(size: 10, weight: .medium)) - .foregroundColor(status == "read" ? Color.green : Color.zxPurple) - .padding(.horizontal, 6).padding(.vertical, 2) - .background((status == "read" ? Color.green : Color.zxPurple).opacity(0.1)) - .clipShape(Capsule()) + Spacer() + Button { + Task { await deleteSource(src) } + } label: { + Image("icon-trash").resizable().scaledToFit().frame(width: 16, height: 16).foregroundColor(Color.zxF03) } } - Spacer() - Button { - Task { await deleteSource(src) } - } label: { - Image("icon-trash").resizable().scaledToFit().frame(width: 16, height: 16).foregroundColor(Color.zxF03) + .padding(.vertical, 14) + .overlay(alignment: .bottom) { + Color.zxHairline.frame(height: 0.5) } } - .padding(.vertical, 14) - .overlay(alignment: .bottom) { - Color.zxHairline.frame(height: 0.5) - } } } } @@ -1065,6 +1074,10 @@ struct KnowledgeDetailPage: View { _vm = StateObject(wrappedValue: KnowledgeDetailViewModel(item: item)) } + @State private var navigateToReader = false + @State private var readerPath: String = "" + @State private var readerType: MaterialType = .text + var body: some View { Group { switch vm.loadState { @@ -1477,6 +1490,18 @@ struct EditKnowledgePage: View { // MARK: - Helpers +private func materialTypeFromMime(_ mime: String?) -> MaterialType { + guard let m = mime?.lowercased() else { return .markdown } + if m.contains("pdf") { return .pdf } + if m.contains("epub") { return .epub } + if m.contains("word") || m.contains("docx") || m.contains("doc") { return .word } + if m.contains("excel") || m.contains("xlsx") { return .excel } + if m.contains("powerpoint") || m.contains("pptx") { return .powerPoint } + if m.contains("image") { return .image } + if m.contains("text/plain") { return .text } + return .markdown +} + private func writeTempFile(content: String, itemId: String) throws -> String { let dir = FileManager.default.temporaryDirectory let url = dir.appendingPathComponent("kd_text_\(itemId).md")