From 011dabcb43ce49ba2ca72021bdceb48c98b7f3e1 Mon Sep 17 00:00:00 2001 From: wangdl Date: Thu, 28 May 2026 20:52:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(ios):=20=E9=87=8D=E5=86=99=20LibraryDetailP?= =?UTF-8?q?age=20body=20=E2=80=94=20=E6=B8=85=E7=90=86=20ZStack/VStack=20?= =?UTF-8?q?=E5=B5=8C=E5=A5=97=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ZStack { Color; VStack { ... } } 结构正确分离 - ScrollView 内 VStack 的 if/else 分支独立清晰 - Source 列表去掉多余外层 VStack Co-Authored-By: Claude Opus 4.7 --- .../Features/Library/LibrarySubpages.swift | 145 +++++++++--------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift b/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift index 3afaf8a..c76ab02 100644 --- a/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift +++ b/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift @@ -149,85 +149,92 @@ struct LibraryDetailPage: View { } var body: some View { - ZStack { Color.zxBg0.ignoresSafeArea(); VStack(spacing: 0) { - Picker("", selection: $detailTab) { - Text("知识点").tag(0) - Text("资料来源").tag(1) - } - .pickerStyle(.segmented) - .padding(.horizontal, 20).padding(.top, 8) + ZStack { + Color.zxBg0.ignoresSafeArea() + VStack(spacing: 0) { + Picker("", selection: $detailTab) { + Text("知识点").tag(0) + Text("资料来源").tag(1) + } + .pickerStyle(.segmented) + .padding(.horizontal, 20).padding(.top, 8) - ScrollView { VStack(spacing: 12) { - if detailTab == 0 { - if viewModel.isLoading && viewModel.items.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.items) { item in - if isSelectMode { - Button { - 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) + ScrollView { + VStack(spacing: 12) { + if detailTab == 0 { + if viewModel.isLoading && viewModel.items.isEmpty { + VStack(spacing: 12) { + ZXLoadingView(size: 36, lineWidth: 3) + Text("加载中…").font(.system(size: 13)).foregroundColor(Color.zxF04) + } + .frame(maxWidth: .infinity).padding(.top, 80) } - } - .foregroundColor(.primary) - } else { - NavigationLink(value: Route.knowledgeDetail(item: item)) { - ZXCardRow(icon: "doc.text", title: item.title, desc: item.summary ?? item.content ?? "", status: item.status ?? "active", c: Color.zxGreen) - } - } - } - 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 { - // 资料来源 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) } + ForEach(viewModel.items) { item in + if isSelectMode { + Button { + 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) } } - Spacer() - Button { - Task { await deleteSource(src) } - } label: { - Image(systemName: "trash").font(.system(size: 14)).foregroundColor(Color.zxF03) + .foregroundColor(.primary) + } else { + NavigationLink(value: Route.knowledgeDetail(item: item)) { + ZXCardRow(icon: "doc.text", title: item.title, desc: item.summary ?? item.content ?? "", status: item.status ?? "active", c: Color.zxGreen) } } - .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) } - } - .padding(.horizontal, 20).padding(.bottom, 80) - .scrollIndicators(.hidden) - .zxPullToRefresh { await viewModel.refresh(knowledgeBaseId: knowledgeBaseId) } + .scrollIndicators(.hidden) + .zxPullToRefresh { await viewModel.refresh(knowledgeBaseId: knowledgeBaseId) } } } .navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()