fix(ios): 重写 LibraryDetailPage body — 清理 ZStack/VStack 嵌套结构
- ZStack { Color; VStack { ... } } 结构正确分离
- ScrollView 内 VStack 的 if/else 分支独立清晰
- Source 列表去掉多余外层 VStack
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
6bb0ae6e29
commit
011dabcb43
@ -149,85 +149,92 @@ struct LibraryDetailPage: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack { Color.zxBg0.ignoresSafeArea(); VStack(spacing: 0) {
|
ZStack {
|
||||||
Picker("", selection: $detailTab) {
|
Color.zxBg0.ignoresSafeArea()
|
||||||
Text("知识点").tag(0)
|
VStack(spacing: 0) {
|
||||||
Text("资料来源").tag(1)
|
Picker("", selection: $detailTab) {
|
||||||
}
|
Text("知识点").tag(0)
|
||||||
.pickerStyle(.segmented)
|
Text("资料来源").tag(1)
|
||||||
.padding(.horizontal, 20).padding(.top, 8)
|
}
|
||||||
|
.pickerStyle(.segmented)
|
||||||
|
.padding(.horizontal, 20).padding(.top, 8)
|
||||||
|
|
||||||
ScrollView { VStack(spacing: 12) {
|
ScrollView {
|
||||||
if detailTab == 0 {
|
VStack(spacing: 12) {
|
||||||
if viewModel.isLoading && viewModel.items.isEmpty {
|
if detailTab == 0 {
|
||||||
VStack(spacing: 12) { ZXLoadingView(size: 36, lineWidth: 3); Text("加载中…").font(.system(size: 13)).foregroundColor(Color.zxF04) }
|
if viewModel.isLoading && viewModel.items.isEmpty {
|
||||||
.frame(maxWidth: .infinity).padding(.top, 80)
|
VStack(spacing: 12) {
|
||||||
}
|
ZXLoadingView(size: 36, lineWidth: 3)
|
||||||
ForEach(viewModel.items) { item in
|
Text("加载中…").font(.system(size: 13)).foregroundColor(Color.zxF04)
|
||||||
if isSelectMode {
|
}
|
||||||
Button {
|
.frame(maxWidth: .infinity).padding(.top, 80)
|
||||||
if selectedIds.contains(item.id) { selectedIds.remove(item.id) }
|
|
||||||
else { selectedIds.insert(item.id) }
|
|
||||||
} label: {
|
|
||||||
HStack(spacing: 10) {
|
|
||||||
Image(systemName: selectedIds.contains(item.id) ? "checkmark.circle.fill" : "circle")
|
|
||||||
.font(.system(size: 20))
|
|
||||||
.foregroundColor(selectedIds.contains(item.id) ? Color.zxPrimary : Color.zxF03)
|
|
||||||
ZXCardRow(icon: "doc.text", title: item.title, desc: item.summary ?? item.content ?? "", status: item.status ?? "active", c: Color.zxGreen)
|
|
||||||
}
|
}
|
||||||
}
|
ForEach(viewModel.items) { item in
|
||||||
.foregroundColor(.primary)
|
if isSelectMode {
|
||||||
} else {
|
Button {
|
||||||
NavigationLink(value: Route.knowledgeDetail(item: item)) {
|
if selectedIds.contains(item.id) { selectedIds.remove(item.id) }
|
||||||
ZXCardRow(icon: "doc.text", title: item.title, desc: item.summary ?? item.content ?? "", status: item.status ?? "active", c: Color.zxGreen)
|
else { selectedIds.insert(item.id) }
|
||||||
}
|
} label: {
|
||||||
}
|
HStack(spacing: 10) {
|
||||||
}
|
Image(systemName: selectedIds.contains(item.id) ? "checkmark.circle.fill" : "circle")
|
||||||
if viewModel.items.isEmpty && !viewModel.isLoading {
|
.font(.system(size: 20))
|
||||||
Text("暂无知识点").font(.system(size: 13)).foregroundColor(Color.zxF03).padding(.top, 40)
|
.foregroundColor(selectedIds.contains(item.id) ? Color.zxPrimary : Color.zxF03)
|
||||||
}
|
ZXCardRow(icon: "doc.text", title: item.title, desc: item.summary ?? item.content ?? "", status: item.status ?? "active", c: Color.zxGreen)
|
||||||
if viewModel.hasMore {
|
|
||||||
ZXLoadMoreFooter { await viewModel.loadMore(knowledgeBaseId: knowledgeBaseId) }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 资料来源 Tab
|
|
||||||
if isLoadingSources {
|
|
||||||
VStack(spacing: 12) { ProgressView().tint(Color.zxPurple); Text("加载中…").font(.system(size: 13)).foregroundColor(Color.zxF04) }.padding(.top, 80)
|
|
||||||
} else if sources.isEmpty {
|
|
||||||
Text("暂无资料来源").font(.system(size: 13)).foregroundColor(Color.zxF03).padding(.top, 40)
|
|
||||||
} else {
|
|
||||||
ForEach(sources) { src in
|
|
||||||
VStack(spacing: 0) {
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
Image(systemName: src.type == "file" ? "doc.fill" : "link")
|
|
||||||
.font(.system(size: 18)).foregroundColor(Color.zxPurple)
|
|
||||||
.frame(width: 40, height: 40).background(Color.zxPurpleBG(0.12)).clipShape(RoundedRectangle(cornerRadius: 10))
|
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
|
||||||
Text(src.title ?? src.originalFilename ?? "未命名").font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0).lineLimit(1)
|
|
||||||
HStack(spacing: 6) {
|
|
||||||
Text(src.parseStatus ?? "pending").font(.system(size: 10, weight: .semibold))
|
|
||||||
.foregroundColor(src.parseStatus == "completed" ? Color.zxGreen : Color.zxAmber)
|
|
||||||
.padding(.horizontal, 6).padding(.vertical, 1)
|
|
||||||
.background((src.parseStatus == "completed" ? Color.zxGreen : Color.zxAmber).opacity(0.12)).clipShape(Capsule())
|
|
||||||
if let len = src.textLength, len > 0 { Text("\(len) 字").font(.system(size: 10)).foregroundColor(Color.zxF04) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
.foregroundColor(.primary)
|
||||||
Button {
|
} else {
|
||||||
Task { await deleteSource(src) }
|
NavigationLink(value: Route.knowledgeDetail(item: item)) {
|
||||||
} label: {
|
ZXCardRow(icon: "doc.text", title: item.title, desc: item.summary ?? item.content ?? "", status: item.status ?? "active", c: Color.zxGreen)
|
||||||
Image(systemName: "trash").font(.system(size: 14)).foregroundColor(Color.zxF03)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(12).background(Color.zxFill003).clipShape(RoundedRectangle(cornerRadius: 14))
|
}
|
||||||
|
if viewModel.items.isEmpty && !viewModel.isLoading {
|
||||||
|
Text("暂无知识点").font(.system(size: 13)).foregroundColor(Color.zxF03).padding(.top, 40)
|
||||||
|
}
|
||||||
|
if viewModel.hasMore {
|
||||||
|
ZXLoadMoreFooter { await viewModel.loadMore(knowledgeBaseId: knowledgeBaseId) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if isLoadingSources {
|
||||||
|
VStack(spacing: 12) {
|
||||||
|
ProgressView().tint(Color.zxPurple)
|
||||||
|
Text("加载中…").font(.system(size: 13)).foregroundColor(Color.zxF04)
|
||||||
|
}.padding(.top, 80)
|
||||||
|
} else if sources.isEmpty {
|
||||||
|
Text("暂无资料来源").font(.system(size: 13)).foregroundColor(Color.zxF03).padding(.top, 40)
|
||||||
|
} else {
|
||||||
|
ForEach(sources) { src in
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Image(systemName: src.type == "file" ? "doc.fill" : "link")
|
||||||
|
.font(.system(size: 18)).foregroundColor(Color.zxPurple)
|
||||||
|
.frame(width: 40, height: 40).background(Color.zxPurpleBG(0.12)).clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text(src.title ?? src.originalFilename ?? "未命名").font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0).lineLimit(1)
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Text(src.parseStatus ?? "pending").font(.system(size: 10, weight: .semibold))
|
||||||
|
.foregroundColor(src.parseStatus == "completed" ? Color.zxGreen : Color.zxAmber)
|
||||||
|
.padding(.horizontal, 6).padding(.vertical, 1)
|
||||||
|
.background((src.parseStatus == "completed" ? Color.zxGreen : Color.zxAmber).opacity(0.12)).clipShape(Capsule())
|
||||||
|
if let len = src.textLength, len > 0 { Text("\(len) 字").font(.system(size: 10)).foregroundColor(Color.zxF04) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
Button {
|
||||||
|
Task { await deleteSource(src) }
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "trash").font(.system(size: 14)).foregroundColor(Color.zxF03)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(12).background(Color.zxFill003).clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.horizontal, 20).padding(.bottom, 80)
|
||||||
}
|
}
|
||||||
}
|
.scrollIndicators(.hidden)
|
||||||
.padding(.horizontal, 20).padding(.bottom, 80)
|
.zxPullToRefresh { await viewModel.refresh(knowledgeBaseId: knowledgeBaseId) }
|
||||||
.scrollIndicators(.hidden)
|
|
||||||
.zxPullToRefresh { await viewModel.refresh(knowledgeBaseId: knowledgeBaseId) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user