- 移除列表中部的虚线"创建新知识库"按钮 - 右上角+按钮从 libraryImport 改为 libraryCreate - 空状态提示更新 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
87 lines
6.5 KiB
Swift
87 lines
6.5 KiB
Swift
//
|
|
// LibraryHomeView.swift - Page 7
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct LibraryHomeView: View {
|
|
@StateObject private var viewModel = LibraryViewModel()
|
|
@State private var s = ""
|
|
var body: some View {
|
|
ZStack { ZXGradient.page.ignoresSafeArea()
|
|
VStack(spacing: 0) {
|
|
HStack { Text("知识库").font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxF0).tracking(-0.5); Spacer()
|
|
NavigationLink(value: Route.librarySearch) {
|
|
Image(systemName: "magnifyingglass").font(.system(size: 18)).foregroundColor(Color.zxF05)
|
|
.frame(width: 36, height: 36).background(Color(hex:"#FFFFFF",opacity:0.05))
|
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
|
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.zxBorder008, lineWidth: 1))
|
|
}
|
|
.accessibilityLabel("搜索知识库")
|
|
NavigationLink(value: Route.libraryCreate) {
|
|
Image(systemName: "plus").font(.system(size: 18)).foregroundColor(.white)
|
|
.frame(width: 36, height: 36).background(ZXGradient.brand)
|
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
|
}
|
|
.accessibilityLabel("创建新知识库")
|
|
}
|
|
.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 12)
|
|
HStack(spacing: 8) { Image(systemName: "magnifyingglass").font(.system(size: 16)).foregroundColor(Color.zxF03); TextField("搜索知识库或知识点…", text: $s).font(.system(size: 14)).tint(Color.zxPurple).accessibilityLabel("搜索知识库") }
|
|
.padding(.horizontal, 14).frame(height: 44).background(Color.zxFill004).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 14)).padding(.horizontal, 20).padding(.bottom, 16)
|
|
.accessibilityHint("输入关键词搜索知识库或知识点")
|
|
ScrollView { VStack(spacing: 12) {
|
|
if viewModel.isLoading && viewModel.knowledgeBases.isEmpty {
|
|
VStack(spacing: 12) { ZXLoadingView(size: 36, lineWidth: 3); Text("加载中…").font(.system(size: 13)).foregroundColor(Color.zxF04) }
|
|
.frame(maxWidth: .infinity).padding(.top, 80)
|
|
}
|
|
ForEach(viewModel.knowledgeBases) { kb in
|
|
NavigationLink(value: Route.libraryDetail(knowledgeBaseId: kb.id)) {
|
|
ZLibraryCard(icon: "books.vertical.fill", name: kb.title, desc: kb.description ?? "", color: Color.zxPurple, items: kb.itemCount ?? 0, mastery: 50, tags: [], last: lastStudiedText(kb.lastStudiedAt))
|
|
}
|
|
}
|
|
if viewModel.knowledgeBases.isEmpty && !viewModel.isLoading {
|
|
Text("还没有知识库,点击右上角 + 创建").font(.system(size: 14)).foregroundColor(Color.zxF04).padding(.top, 60)
|
|
}
|
|
if viewModel.hasMore {
|
|
ZXLoadMoreFooter { await viewModel.loadMore() }
|
|
}
|
|
}.padding(.horizontal, 20).padding(.bottom, 120) }
|
|
.scrollIndicators(.hidden)
|
|
.zxPullToRefresh { await viewModel.refresh() }
|
|
}
|
|
}
|
|
.task { await viewModel.loadKnowledgeBases() }
|
|
.navigationDestination(for: Route.self) { $0.destination }
|
|
}
|
|
|
|
private func lastStudiedText(_ iso: String?) -> String {
|
|
guard let iso else { return "未学习" }
|
|
return iso.prefix(10).description
|
|
}
|
|
}
|
|
struct ZLibraryCard: View { let icon: String; let name: String; let desc: String; let color: Color; let items: Int; let mastery: Int; let tags: [String]; let last: String
|
|
var body: some View { VStack(spacing: 0) { Rectangle().fill(ZXGradient.progressBar).frame(height: 3); HStack(spacing: 12) { Image(systemName: icon).font(.system(size: 20)).foregroundColor(color).frame(width: 44, height: 44).background(color.opacity(0.12)).clipShape(RoundedRectangle(cornerRadius: 13)).overlay(RoundedRectangle(cornerRadius: 13).stroke(color.opacity(0.3), lineWidth: 1)); VStack(alignment: .leading, spacing: 2) { Text(name).font(.system(size: 16, weight: .bold)).foregroundColor(Color.zxF0); Text(desc).font(.system(size: 12)).foregroundColor(Color.zxF04); Text("掌握 \(mastery)%").font(.system(size: 11)).foregroundColor(Color.zxF04) }; Spacer() }.padding(16); HStack { HStack(spacing: 4) { Image(systemName: "clock").font(.system(size: 10)); Text("\(items) 项 · \(last)").font(.system(size: 11)) }.foregroundColor(Color.zxF03); Spacer(); ForEach(tags.prefix(2), id: \.self) { t in Text(t).font(.system(size: 10, weight: .medium)).foregroundColor(Color.zxPurple).padding(.horizontal, 7).padding(.vertical, 2).background(Color(hex: "#7C6EFA", opacity: 0.08)).clipShape(Capsule()) } }.padding(.horizontal, 16).padding(.bottom, 12) }
|
|
.background(Color.zxFill003).clipShape(RoundedRectangle(cornerRadius: 20)).overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.zxBorder006, lineWidth: 1)) }
|
|
}
|
|
|
|
struct LibrarySearchView: View {
|
|
@State private var query = ""
|
|
var body: some View {
|
|
ZStack { Color.zxBg0.ignoresSafeArea()
|
|
VStack(spacing: 0) {
|
|
HStack(spacing: 8) { Image(systemName: "magnifyingglass").font(.system(size: 16)).foregroundColor(Color.zxF03); TextField("搜索知识库或知识点…", text: $query).font(.system(size: 14)).tint(Color.zxPurple) }
|
|
.padding(.horizontal, 14).frame(height: 44).background(Color.zxFill004).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 14))
|
|
.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 16)
|
|
ScrollView { VStack(spacing: 12) {
|
|
if query.isEmpty {
|
|
VStack(spacing: 12) {
|
|
Image(systemName: "magnifyingglass").font(.system(size: 36)).foregroundColor(Color.zxF03)
|
|
Text("搜索知识点、知识库或标签").font(.system(size: 13)).foregroundColor(Color.zxF03)
|
|
}.padding(.top, 80)
|
|
}
|
|
}.padding(.horizontal, 20) }.scrollIndicators(.hidden)
|
|
}
|
|
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar)
|
|
}
|
|
}
|